/**
 * theme.css — Drop UI
 *      Persistent Gaussian "tab" hanging from the top edge — the sliver-peek
 *      of the "3" is always visible. On hover (desktop), the curve descends
 *      and the "3" fully reveals (peeked). On click/tap (any device), the
 *      spotlight panel drops below the curve (active). Esc or selection
 *      reverts to rest.
 *
 *      DOM is injected by theme.js (index.html stays untouched). Color scheme
 *      is the 3eff palette by default; client variants override the
 *      --drop-* tokens in a wrapping rule (e.g. [data-client="bayer"]).
 *
 * author: $Author$
 * revision: $Rev$
 * revision date: $Date$
 */

:root {
    /* Drop-private theme-internal compositions and geometry.
       Color/surface vars come from --tapp_* tokens (set by base.css and
       overridden by the active palette); only Drop-specific overlays,
       brand-derived tints, and animation geometry stay drop-named. */

    /* Brand-derived tints for the gaussian drop and background grid. Use
       color-mix() so the active palette's brand color drives them. */
    --drop-bg-grid:    color-mix(in srgb, var(--tapp_brand-primary) 4%,  transparent);
    --drop-curve-tint: color-mix(in srgb, var(--tapp_brand-primary) 18%, transparent);

    /* Triadic brand accents — derived from --tapp_brand-primary via
       OKLCH relative-color syntax. The framework owns the math here
       so any palette gets accent-a / accent-b for free; palettes that
       declare them explicitly still win (palette CSS loads before
       Drop's, so a palette `:root` value sets the floor; Drop's `:root`
       overrides with the derived value — last-declared wins).
       To pin literal accent values for a specific palette, use
       higher specificity than `:root` (e.g. `[data-palette="X"] :root`)
       or load the palette AFTER Drop.

       Math: classic triadic hue rotation (±120°) with a chroma
       CEILING via `min(0.13, c)`. L is inherited from primary
       unchanged. Saturated primaries (sl052 Takeda red at C≈0.24,
       sl104 Exact purple at C≈0.27) get their accent chroma capped
       so the triadic neighbor doesn't inherit the primary's full
       saturation and end up "shouting" at the user. Already-muted
       primaries (3eff at C≈0.131) stay essentially unchanged —
       the cap of 0.13 was chosen to land just under 3eff's
       saturation, so its accent feel doesn't change. Earlier
       passes tried h±60° (kept too close to primary on saturated
       palettes) and various L/C boosts at ±120° (made every
       palette louder than its primary). Chroma cap + ±120°
       resolves both endpoints: triadic enough to read as a
       different brand color, muted enough not to dominate. */

       The 3eff palette's literal accent values were the previous
       fallback; deleted now that Drop owns the derivation.
       Browsers: relative-color syntax in declarations is supported
       on Chromium 119+, Safari 16.4+, Firefox 128+ (all 2024 or
       earlier — universal by now). The "nested in color-mix" issue
       from the old 3eff comment doesn't apply here — color-mix
       consumers receive an already-resolved var(--accent-*) value. */
    --tapp_brand-accent-a: oklch(from var(--tapp_brand-primary) l min(0.13, c) calc(h + 120));
    --tapp_brand-accent-b: oklch(from var(--tapp_brand-primary) l min(0.13, c) calc(h - 120));

    /* Topbar overlays — neutral white/black tints for the frosted-glass
       effect. Not coupled to the brand palette. */
    --drop-topbar-bg:     rgba(255, 255, 255, 0.72);
    --drop-topbar-border: rgba(0,   0,   0,   0.06);
    --drop-topbar-hover:  rgba(0,   0,   0,   0.06);
    --drop-topbar-press:  rgba(0,   0,   0,   0.10);
    --drop-topbar-pill:   rgba(0,   0,   0,   0.05);
    --drop-topbar-icon-stroke: %23444;

    /* Bell + image animation magnitudes (geometry, not palette) */
    --drop-bell-peeked: 14px;    /* bell translate at hover */
    --drop-bell-active: 100px;   /* bell translate at open (bell center → viewport y=100) */
    --drop-bell-active-scale: 1.5;
    /* Image at rest is centered at (100, 18) in viewBox; bell at active ends
       at (100, 100). For the image to land centered on the bell at active,
       its translateY = 100 - 18 = 82px (compensates the rest offset). */
    --drop-image-active: 82px;
    --drop-image-active-scale: 2.4;
    --drop-spotlight-top: 200px; /* where the panel anchors when active */
    --drop-logo-landing: 280px;

    /* Vertical clearance for feature content so it isn't hidden behind the
       fixed topbar (36px) and the gaussian drop's overhang. */
    --drop-content-top: 56px;

    --drop-ease-soft:   cubic-bezier(0.22, 0.61, 0.36, 1);
    --drop-ease-spring: cubic-bezier(0.34, 1.4,  0.64, 1);
}

/* ============================================
   Base canvas (no horizontal header strip in Drop)
   ============================================ */

*, *::before, *::after { box-sizing: border-box; }

body {
    margin: 0;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    font-size: 14px;
    line-height: 1.4;
    color: var(--tapp_theme-text);
    background: var(--tapp_theme-background);
    background-image:
        linear-gradient(var(--drop-bg-grid) 1px, transparent 1px),
        linear-gradient(90deg, var(--drop-bg-grid) 1px, transparent 1px);
    background-size: 32px 32px;
    overflow: hidden;
    height: 100vh;
}

/* Footer is hidden in Drop; the header is styled as the frosted topbar
   below. The landing logo (#tapp_landing_logo) renders the framework's
   default 3app image; size/spacing for it is set in the landing block. */
#tapp_footer {
    display: none;
}

/* ============================================
   Header → Drop topbar
   Drop styles the framework's #tapp_header in place (no parallel
   injection). Frosted-glass strip pinned to the top, with the brand /
   loaded-title on the left and the app-controls cluster on the right.
   The modules nav lives in the spotlight (moved by adoptModules()),
   not in the header itself.
   ============================================ */

#tapp_header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    /* Below the gaussian-drop curve (z=50) so the bell drops in front;
       above the workspace and backdrop. */
    z-index: 30;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 12px;
    background: var(--drop-topbar-bg);
    border-bottom: 1px solid var(--drop-topbar-border);
    backdrop-filter: blur(10px) saturate(140%);
    -webkit-backdrop-filter: blur(10px) saturate(140%);
    font-size: 12px;
    color: var(--tapp_theme-text);
}

/* Hide the section headings — Drop's topbar reads as icons + a single
   loaded-title pill, not labeled groups. */
#tapp_header .tapp_nav_heading {
    display: none;
}

/* Brand: hide the header link (just whitespace) and tagline; the loaded-
   title pill below acts as the left-side identity marker. */
#tapp_brand {
    display: none;
}

/* Loaded-title pill: #tapp_loaded_group is the pill container.
   It wraps the title <p> and the gear <button> so the gear appears
   inside the pill. States:
     - Empty (title data-empty=1): transparent + muted text + muted cube.
     - Loaded:                     brand-colored pill + inverted text + cube. */
#tapp_loaded_group {
    display:     inline-flex;
    align-items: center;
    gap:         6px;
    flex-shrink: 0;
    /* Pill */
    padding:      4px 10px 4px 8px;
    border-radius: 999px;
    background:   var(--tapp_brand-primary);
    font-weight:  600;
    color:        var(--tapp_theme-text-inverted);
    max-width:    42vw;
}

/* Rubik-style 3D cube glyph on the group (was on #tapp_loaded_title). */
#tapp_loaded_group::before {
    content: '';
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    background-color: currentColor;
    -webkit-mask: no-repeat center / contain url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M12 2 L4 6.5 L4 17.5 L12 22 L20 17.5 L20 6.5 Z'/><path d='M4 6.5 L12 11 L20 6.5'/><path d='M12 11 L12 22'/><path d='M9.33 4 L17.33 8.5'/><path d='M6.67 5.5 L14.67 10'/><path d='M9.33 12.67 L9.33 20.67'/><path d='M14.67 12.67 L14.67 20.67'/></svg>");
            mask: no-repeat center / contain url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'><path d='M12 2 L4 6.5 L4 17.5 L12 22 L20 17.5 L20 6.5 Z'/><path d='M4 6.5 L12 11 L20 6.5'/><path d='M12 11 L12 22'/><path d='M9.33 4 L17.33 8.5'/><path d='M6.67 5.5 L14.67 10'/><path d='M9.33 12.67 L9.33 20.67'/><path d='M14.67 12.67 L14.67 20.67'/></svg>");
}

/* Empty state: no file loaded — transparent pill + muted cube. */
#tapp_loaded_group:has(#tapp_loaded_title[data-empty="1"]) {
    background:  transparent;
    font-weight: 400;
    color:       var(--tapp_theme-text-muted);
}

/* Title <p>: bare text only — pill styling now on the group. */
#tapp_loaded_title {
    margin:    0;
    padding:   0;
    background: transparent;
    font-weight: inherit;
    color:      inherit;
    min-width:  0;        /* allow flex shrink so long names truncate */
    overflow:   hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    display:    block;
}

/* Gear button — sits inside the pill as last flex child.
   A thin left separator + inherits pill color so it blends.
   Hidden via [hidden] attr when no file is loaded. */
.tapp_filesettings_btn {
    flex-shrink: 0;
    padding:     0 2px 0 8px;
    background:  transparent;
    border:      none;
    border-left: 1px solid color-mix(in srgb, currentColor 35%, transparent);
    color:       inherit;
    cursor:      pointer;
    font-size:   12px;
    line-height: 1;
    opacity:     0.65;
    transition:  opacity 120ms;
}
.tapp_filesettings_btn:hover { opacity: 1; }

/* Modules nav is moved into the spotlight by adoptModules(); when it's
   still in the header (during cleanup or before init), don't show it. */
#tapp_header > #tapp_nav_modules {
    display: none;
}

/* Module-tools nav: its toolbar (#tapp_tools) is feature-populated. Keep
   it inline-flex so any tool buttons feature code adds appear in the
   topbar without extra layout. Hide when empty. */
#tapp_header > #tapp_nav_tools .tapp_toolbar {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
#tapp_header > #tapp_nav_tools .tapp_toolbar:empty {
    display: none;
}

/* App-controls cluster on the right (Home / Open / Lang / Theme /
   Profile / Logout) — wrapped in a pill that mirrors the loaded-title
   pill on the left. */
#tapp_header > #tapp_nav_app .tapp_controls {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    margin: 0;
    padding: 2px 4px;
    list-style: none;
    background: var(--drop-topbar-pill);
    border-radius: 999px;
}
#tapp_header > #tapp_nav_app .tapp_controls_item {
    display: inline-flex;
    align-items: center;
}

/* Buttons: 28×28 icon-style, circular hover. Theme paints icons via
   background-image; the framework's text labels are sized to 0 so they
   read on bare HTML but disappear when iconized. */
#tapp_header .tapp_menu_btn,
#tapp_header .tapp_btn {
    width: 28px;
    height: 28px;
    padding: 0;
    border: 0;
    background-color: transparent;
    color: var(--tapp_theme-text);
    border-radius: 50%;
    font-size: 0;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
#tapp_header .tapp_menu_btn:hover,
#tapp_header .tapp_btn:hover {
    background-color: var(--drop-topbar-hover);
}
#tapp_header .tapp_menu_btn:active,
#tapp_header .tapp_btn:active {
    background-color: var(--drop-topbar-press);
}
#tapp_header .tapp_menu_btn kbd {
    display: none; /* hide the framework's "Ctrl+Shift+O" hint */
}

/* Language: hide the framework's text label, expose the native <select>
   as a plain icon-sized control. Theme-side dark-mode override below
   swaps the globe icon to the lighter variant. */
#tapp_header .tapp_label {
    display: none;
}
#tapp_header .tapp_select {
    width: 28px;
    height: 28px;
    padding: 0;
    border: 0;
    background-color: transparent;
    color: transparent;
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    text-indent: -9999px;
    border-radius: 50%;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='10'/><path d='M2 12h20'/><path d='M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z'/></svg>");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 16px 16px;
}
#tapp_header .tapp_select:hover {
    background-color: var(--drop-topbar-hover);
}
#tapp_header .tapp_select option {
    color: var(--tapp_theme-text);
    background: var(--tapp_theme-surface);
    text-indent: 0;
}

/* Active-language indicator — small corner badge over the globe's
   lower-right. The wrapper provides the positioning context so the
   badge anchors to the icon. */
#tapp_header .tapp_lang_wrap {
    position: relative;
    display: inline-block;
    line-height: 0;          /* keep the wrapper flush with the 28px globe */
}
#tapp_header .tapp_active_lang {
    position: absolute;
    right: -2px;
    bottom: -2px;
    min-width: 16px;
    height: 14px;
    padding: 0 4px;
    border-radius: 999px;
    font-size: 9px;
    font-weight: 700;
    line-height: 14px;
    letter-spacing: 0.04em;
    text-align: center;
    color: var(--tapp_active_lang-text);
    background: var(--tapp_active_lang-bg);
    /* Soft outline so the badge separates from the icon underneath. */
    box-shadow: 0 0 0 1.5px var(--tapp_theme-background);
    pointer-events: none;
}

/* Theme switch — render the framework's <input type="checkbox"> as an
   icon button (moon when light, sun when dark). The visible <label
   class="tapp_switch"> wraps the checkbox; we hide the checkbox itself
   and paint the moon/sun icon as a background on the wrapping label. */
#tapp_header .tapp_switch {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    cursor: pointer;
    background-color: transparent;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z'/></svg>");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 16px 16px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
#tapp_header .tapp_switch:hover { background-color: var(--drop-topbar-hover); }
#tapp_header .tapp_switch input,
#tapp_header .tapp_switch_slider { display: none; }

/* Dark mode: swap to sun icon (and lighter stroke for contrast) */
:root[tapp-theme="dark"] #tapp_header .tapp_switch {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23e0e4ea' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='4'/><path d='M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41'/></svg>");
}

/* Profile button — user-circle icon */
#tapp_header #tapp_profile {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='8' r='4'/><path d='M4 21a8 8 0 0 1 16 0'/></svg>");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 16px 16px;
}
:root[tapp-theme="dark"] #tapp_header #tapp_profile {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23e0e4ea' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='8' r='4'/><path d='M4 21a8 8 0 0 1 16 0'/></svg>");
}

/* Home / Open / Logout — same icon-button treatment */
#tapp_header #tapp_home {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z'/><path d='M9 22V12h6v10'/></svg>");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 16px 16px;
}
#tapp_header #tapp_file_open_local {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M6 14 7.5 11.1A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.55 6a2 2 0 0 1-1.94 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2'/></svg>");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 16px 16px;
}
#tapp_header #tapp_file_open_library {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M4 4v16'/><path d='M8 6v14'/><path d='M12 4v16'/><path d='m17 5 3.5 14.5'/></svg>");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 16px 16px;
}
#tapp_header #tapp_logout {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4'/><path d='M16 17l5-5-5-5'/><path d='M21 12H9'/></svg>");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 16px 16px;
}
:root[tapp-theme="dark"] #tapp_header #tapp_home,
:root[tapp-theme="dark"] #tapp_header #tapp_file_open_local,
:root[tapp-theme="dark"] #tapp_header #tapp_file_open_library,
:root[tapp-theme="dark"] #tapp_header #tapp_logout {
    /* Strokes use #e0e4ea in dark — recompose data URLs */
    /* Simpler: invert the icons via a filter so we don't repeat the SVGs */
    filter: brightness(0) invert(0.85);
}

/* Walkthrough prev/next — a pill that sits just right of the loaded-title
   on the left. margin-right:auto glues it to the title and pushes the
   app-controls cluster to the far right. Hidden unless a tour is active. */
#tapp_header > #tapp_walk_nav {
    display: inline-flex;
    align-items: center;
    margin-left: 8px;
    margin-right: auto;
}
#tapp_header > #tapp_walk_nav[hidden] { display: none; }
#tapp_header > #tapp_walk_nav .tapp_controls {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    margin: 0;
    padding: 2px 4px;
    list-style: none;
    background: var(--drop-topbar-pill);
    border-radius: 999px;
}
#tapp_header > #tapp_walk_nav .tapp_controls_item {
    display: inline-flex;
    align-items: center;
}
#tapp_header #tapp_walk_prev {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='15 4 7 12 15 20'/></svg>");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 16px 16px;
}
#tapp_header #tapp_walk_next {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='9 4 17 12 9 20'/></svg>");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 16px 16px;
}
#tapp_header .tapp_menu_btn:disabled {
    opacity: 0.3;
    cursor: default;
    pointer-events: none;
}
:root[tapp-theme="dark"] #tapp_header #tapp_walk_prev,
:root[tapp-theme="dark"] #tapp_header #tapp_walk_next {
    filter: brightness(0) invert(0.85);
}

/* Push the workspace below the fixed topbar */
#tapp_workspace {
    top: 36px;
}

#tapp_workspace {
    position: fixed;
    inset: 0;
    overflow: hidden;
}

/* Feature panels live as <section data-feature> children of the workspace.
   Option 1 — frosted glass card: the whole feature panel is one floating
   surface (translucent bg, blur, hairline border, soft shadow, big radius).
   Inset from the viewport edges so it reads as a card, not a slab. The
   feature builder controls the content layout inside. */
/* Transparent layout container. The visible "card" is painted on the body
   children (right column); the sidebar fills the full height in the left
   column, brand-coloured, with the framework's <h2> embedded vertically. */
#tapp_workspace > section.tapp_feature_section:not([hidden]) {
    position: absolute;
    top: var(--drop-content-top);
    left: 16px;
    right: 16px;
    bottom: 16px;
    /* `auto` (not hidden) so vertically-tall content — Model details
       subsections (600px) + References below — can scroll inside the
       section instead of being clipped at the bottom. */
    overflow: auto;
    background: transparent;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    padding: 0;
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: 18px;
    align-items: stretch;
    transition: column-gap 240ms var(--drop-ease-soft);
}
/* When the sidebar is expanded, push the body card right to open a gap
   where the section labels float — the sidebar pill itself stays put. */
#tapp_workspace > section.tapp_feature_section:not([hidden]):has(> nav.tapp_feature_nav[data-tapp-nav-expanded="true"]) {
    column-gap: 200px;
}

/* Identifier strip — restyle the framework's auto-injected <h2> (set in
   main.js activateFeature: "<modName> / <feature> [tier-badge]") into a
   full-width brand-colored header at the top of the feature card. The h2
   is always the first child of section.tapp_feature_section, so :first-child
   keeps us from touching any h2 the feature builder may use deeper down.
   Negative margins break out of the card padding so the strip spans
   edge-to-edge and hugs the card's top rounded corners. */
/* Framework <h2> stays display:none while it's a direct child of the
   section — theme.js moves it into the feature's toolbar where it
   reappears as a brand-tinted pill (see .drop_section_title below).
   If a feature has no toolbar the h2 stays here and remains hidden;
   the heading is still in the DOM for assistive tech. */
#tapp_workspace > section.tapp_feature_section > h2 {
    display: none;
}

/* h2 relocated into the feature toolbar — brand-tinted pill at the
   toolbar's start. The toolbar itself is the absolutely-positioned
   "fosa" pill that bites the body card's corner, so this h2 just
   joins its flex layout as the first child. */
.tapp_toolbar > h2.drop_section_title {
    margin: 0;
    padding: 4px 14px;
    display: inline-flex;
    align-items: center;
    border-radius: 999px;
    background: var(--tapp_brand-primary);
    color: var(--tapp_theme-text-inverted);
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    white-space: nowrap;
    line-height: 1;
}

/* Empty feature nav — theme.js marks navs with < 2 sub-sections as
   data-tapp-nav-empty="true"; collapse them so the workspace gets the
   horizontal space back. Specificity matches the main feature-nav rule
   (1,2,2), so it wins on source order. */
#tapp_workspace > section.tapp_feature_section > nav.tapp_feature_nav[data-tapp-nav-empty="true"] {
    display: none;
}
/* When the nav is hidden, collapse the grid to a single workspace column
   so there's no orphan gap on the left. The body-card rule below sets
   grid-column: 2 on every non-h2/nav/arrows/toolbar direct child — that
   would create an *implicit* col 2 here (pushing content right). Force
   those children back into col 1 in the empty-nav variant. */
#tapp_workspace > section.tapp_feature_section:has(> nav.tapp_feature_nav[data-tapp-nav-empty="true"]) {
    grid-template-columns: 1fr;
    column-gap: 0;
}
#tapp_workspace > section.tapp_feature_section:has(> nav.tapp_feature_nav[data-tapp-nav-empty="true"]) > *:not(h2):not(nav):not(.drop_section_arrows_pill):not(.tapp_toolbar) {
    grid-column: 1;
}

/* Section-cycle arrows — two free-floating circles in the top-right of
   the feature section. Skipped by theme.js when fewer than 2 sub-sections. */
/* Section-cycle arrows pill — bites the body card's top-right corner,
   mirroring the toolbar pill on the top-left. Same chrome (curve-tint
   bg, no border, soft shadow), same biting technique:
     - top: 0; right: 0  → flush with the body card's outer edge.
     - border-radius: top-right matches the card's 18 px curve; the other
       three are pill-rounded.
   The "canal" is the empty space below + to the left of the pill (the
   card's frosted bg shows through). */
.drop_section_arrows_pill {
    position: absolute;
    /* Positioned relative to the feature section (which has no border and
       stretches the body card flush to its edges), so top:0/right:0 puts
       the pill's outer edge AT the body card's outer edge. The pill's
       4 px trench border then sits exactly on top of the body card's
       4 px right + top borders, merging into one continuous trench.
       (The toolbar uses negative offsets because IT is inside the body
       card, which has a 4 px border to overlap; this pill is one level up
       in the DOM, where there's no border to compensate for.) */
    top: 0;
    right: 0;
    height: 32px;
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 0 6px;
    background: var(--drop-curve-tint);
    color: var(--tapp_theme-text);
    /* "Fosa" border — matches the toolbar pill's trench treatment. */
    border: 4px solid var(--tapp_theme-background);
    /* Full pill — same as toolbar; the "biting the corner" effect is
       positional, not shape-based. */
    border-radius: 9999px;
    box-shadow: none;
    z-index: 5;
}

/* Individual arrow buttons inside the pill — circular, transparent until
   hover. Position is dictated by the parent flex layout, not absolute. */
.drop_section_arrow {
    width: 24px;
    height: 24px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    background: transparent;
    color: var(--tapp_theme-text);
    border: 0;
    border-radius: 50%;
    cursor: pointer;
    transition: background-color 160ms, color 160ms;
}
.drop_section_arrow:hover {
    background: var(--tapp_brand-primary);
    color: var(--tapp_theme-text-inverted);
}
.drop_section_arrow svg {
    width: 12px;
    height: 12px;
}

/* Toolbar pill — bites the body card's top-left corner via absolute
 * positioning (the previous flow-based negative-margin approach was
 * being clipped by the card's overflow: auto). The body card is given
 * `position: relative` below, and `padding-top` is increased when a
 * toolbar is present so the table content below has room.
 *
 *   - top: 0; left: 0 → flush with the body card's inner border edge.
 *   - Top-left border-radius matches the card's 18 px corner; right +
 *     bottom + bottom-left are pill-rounded.
 *   - Background is the tinted brand color (curve-tint) — clearly
 *     distinct from the card's frosted surface.
 *
 * The toolbar is created by TApp.createToolbar inside a subsection, so
 * the descendant combinator catches it regardless of nesting depth. */
#tapp_workspace > section.tapp_feature_section .tapp_toolbar {
    position: absolute;
    /* Negative offsets equal to the card's 4 px border width — the pill's
       trench border overlaps the card's border, so they merge into a
       single trench on every side the pill touches. Requires the body
       card's overflow to be visible (set below). */
    top: -4px;
    left: -4px;
    /* Must exceed thead th's z-index (2) so the toolbar's stacking context
       beats the sticky header; the multiselect dropdown (z-index: 99000
       inside this context) then correctly renders above the table. */
    z-index: 10;
    display: flex;
    width: max-content;
    /* Cap the width so it doesn't push past the card on the right. The
       card's outer width is 100% + 8 px (4 px border each side); subtract
       the right border + a little headroom. */
    max-width: calc(100% + 4px);
    align-items: center;
    gap: 8px;
    padding: 4px 14px;
    margin: 0;
    background: var(--drop-curve-tint);
    color: var(--tapp_theme-text);
    /* "Fosa" border — same color as the page canvas, so the border reads
       like a trench cut through the card, exposing the page color around
       the toolbar. No shadow (which would imply rising); the heavy border
       implies sinking. */
    border: 4px solid var(--tapp_theme-background);
    /* All four corners full pill — the toolbar is a regular pill shape; the
       "biting the corner" effect comes from positioning at top: 0; left: 0
       and the trench border, not from per-corner radius adjustment. */
    border-radius: 9999px;
    /* Two hairline rings:
         inset 1px → inside the trench (matches the body card's inner rim)
         outer 1px → traces the pill's *outer* edge so the corner-bite
                     shows a visible gray curve against the card body
                     (which otherwise just shows the page-color trench). */
    box-shadow:
        inset 0 0 0 1px var(--tapp_theme-border),
        0 0 0 1px var(--tapp_theme-border);
    box-sizing: border-box;
}
/* Empty toolbar — no chrome, no space taken. */
#tapp_workspace > section.tapp_feature_section .tapp_toolbar:empty {
    display: none;
}

/* Toolbar buttons inside the pill — circular icon-style by default;
   the primary variant is a wider filled pill (matches the action role).
   24 px row height — kept uniform across button / multiselect chip /
   select input so the toolbar reads as a slim strip, not a chunky
   bar. Native <select> (browser internal chrome) renders ~2 px
   taller than declared but the variance is small enough to not
   break the row baseline at this scale. */
.tapp_toolbar > .tapp_toolbar_button,
.tapp_toolbar_actions > .tapp_toolbar_button {
    width: 24px;
    height: 24px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    background: transparent;
    color: var(--tapp_theme-text);
    border: 0;
    border-radius: 50%;
    cursor: pointer;
    font: 12px/1 inherit;
    transition: background-color 160ms, color 160ms;
}
.tapp_toolbar > .tapp_toolbar_button:hover,
.tapp_toolbar_actions > .tapp_toolbar_button:hover {
    /* Longhand: 'background' shorthand would wipe data-icon's
       background-image and the icon would disappear on hover. */
    background-color: var(--tapp_brand-primary);
    color: var(--tapp_theme-text-inverted);
}
.tapp_toolbar > .tapp_toolbar_button svg,
.tapp_toolbar_actions > .tapp_toolbar_button svg {
    width: 14px;
    height: 14px;
}
/* Primary action — wider, filled. */
.tapp_toolbar > .tapp_toolbar_button-primary {
    width: auto;
    height: 24px;
    padding: 0 12px;
    background: var(--tapp_brand-secondary);
    color: var(--tapp_theme-text-inverted);
    border-radius: 12px;
    font-weight: 500;
}
.tapp_toolbar > .tapp_toolbar_button-primary:hover {
    background: var(--tapp_theme-link-hover);
    color: var(--tapp_theme-text-inverted);
}
.tapp_toolbar > .tapp_toolbar_button-destructive {
    width: auto;
    height: 24px;
    padding: 0 12px;
    background: var(--tapp_status-error);
    color: var(--tapp_theme-text-inverted);
    border-radius: 12px;
    font-weight: 500;
}

/* Labels (standalone in the toolbar, OR inside a control wrapper). */
.tapp_toolbar > .tapp_toolbar_label,
.tapp_toolbar_control > .tapp_toolbar_label {
    font-size: 12px;
    color: var(--tapp_theme-text-muted);
    padding: 0;
    margin: 0;
}

/* Section labels with a data-icon hint — small, muted, decorative. The
   text label is hidden via font-size:0 but stays accessible to screen
   readers via tapp-i18n on the element. Known issue: when an icon
   label is immediately followed by a multiselect chip, the icon's
   visual center reads as slightly off the chip's baseline (the chip
   is fine on its own next to buttons / non-multiselect items —
   tcli-epi's Simulation+Run pairing has no problem). Unresolved; the
   Config label in cpr's toolbar is currently emitted without
   `icon:` to dodge it until we can debug properly. */
.tapp_toolbar_label[data-icon] {
    font-size: 0;
    width: 14px;
    /* Match the 26 px height every other toolbar item declares so
       all bounding boxes center on the same row in the toolbar's
       align-items: center flex. The SVG itself stays drawn at
       14 px via the explicit background-size below, centered
       inside the taller box. */
    height: 26px;
    opacity: 0.55;            /* muted: section header, non-interactive */
    background-color: transparent;
    background-repeat: no-repeat;
    background-position: center;
    background-size: 14px 14px;
}
.tapp_toolbar_label[data-icon="view"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M2 12s3-7 10-7 10 7 10 7-3 7-10 7-10-7-10-7Z'/><circle cx='12' cy='12' r='3'/></svg>");
}
.tapp_toolbar_label[data-icon="simulation"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='9'/><polygon points='10,8 17,12 10,16' fill='%23444' stroke='none'/></svg>");
}
.tapp_toolbar_label[data-icon="config"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='3'/><path d='M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z'/></svg>");
}
.tapp_toolbar_label[data-icon="search"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='8'/><path d='m21 21-4.3-4.3'/></svg>");
}
.tapp_toolbar_label[data-icon="page-size"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><line x1='8' x2='21' y1='6' y2='6'/><line x1='8' x2='21' y1='12' y2='12'/><line x1='8' x2='21' y1='18' y2='18'/><line x1='3' x2='3.01' y1='6' y2='6'/><line x1='3' x2='3.01' y1='12' y2='12'/><line x1='3' x2='3.01' y1='18' y2='18'/></svg>");
}
.tapp_toolbar_label[data-icon="warn"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3'/><path d='M12 9v4'/><path d='M12 17h.01'/></svg>");
}
.tapp_toolbar_label[data-icon="currency"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='8' cy='8' r='6'/><path d='M18.09 10.37A6 6 0 1 1 10.34 18'/><path d='M7 6h1v4'/><path d='m16.71 13.88.7.71-2.82 2.82'/></svg>");
}
/* Lucide git-compare — two circles connected by opposing arrows */
.tapp_toolbar_label[data-icon="compare"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='18' cy='18' r='3'/><circle cx='6' cy='6' r='3'/><path d='M13 6h3a2 2 0 0 1 2 2v7'/><path d='M11 18H8a2 2 0 0 1-2-2V9'/></svg>");
}

/* Icon-only action buttons — full-strength stroke, hover background.
   Use longhand `background-color` / `background-image` so the hover
   rule (which sets background-color) doesn't wipe the icon. */
.tapp_toolbar_button[data-icon] {
    font-size: 0;
    background-color: transparent;
    background-repeat: no-repeat;
    background-position: center;
    background-size: 16px 16px;
}
.tapp_toolbar_button[data-icon]:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}
.tapp_toolbar_button[data-icon="chart-hierarchy"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect x='9' y='3' width='6' height='4' rx='1'/><rect x='3' y='17' width='6' height='4' rx='1'/><rect x='15' y='17' width='6' height='4' rx='1'/><path d='M12 7v4M6 17v-2h12v2'/></svg>");
}
.tapp_toolbar_button[data-icon="chart-sunburst"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='3'/><circle cx='12' cy='12' r='6.5'/><circle cx='12' cy='12' r='10'/><path d='M12 2v8M12 14v8M2 12h8M14 12h8'/></svg>");
}
.tapp_toolbar_button[data-icon="zoom-in"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='7'/><path d='m21 21-4.3-4.3'/><path d='M11 8v6'/><path d='M8 11h6'/></svg>");
}
.tapp_toolbar_button[data-icon="zoom-out"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='7'/><path d='m21 21-4.3-4.3'/><path d='M8 11h6'/></svg>");
}
.tapp_toolbar_button[data-icon="zoom-fit"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M3 7V5a2 2 0 0 1 2-2h2'/><path d='M17 3h2a2 2 0 0 1 2 2v2'/><path d='M21 17v2a2 2 0 0 1-2 2h-2'/><path d='M7 21H5a2 2 0 0 1-2-2v-2'/></svg>");
}
/* view-chart: hierarchical-tree glyph (3 nodes + connectors) — the
   tcli/epi chart is a tree flowchart, not a bar chart. Same shape
   as the chart-hierarchy data-icon. */
.tapp_toolbar_button[data-icon="view-chart"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect x='9' y='3' width='6' height='4' rx='1'/><rect x='3' y='17' width='6' height='4' rx='1'/><rect x='15' y='17' width='6' height='4' rx='1'/><path d='M12 7v4M6 17v-2h12v2'/></svg>");
}
/* view-table: 3-row grid — "show the table view". */
.tapp_toolbar_button[data-icon="view-table"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect x='3' y='4' width='18' height='16' rx='1'/><path d='M3 10h18M3 16h18M10 4v16'/></svg>");
}
/* fullscreen: four outward diagonals — "enter fullscreen". */
.tapp_toolbar_button[data-icon="fullscreen"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M9 9 L3 3 M3 3 L8 3 M3 3 L3 8'/><path d='M15 9 L21 3 M21 3 L16 3 M21 3 L21 8'/><path d='M9 15 L3 21 M3 21 L8 21 M3 21 L3 16'/><path d='M15 15 L21 21 M21 21 L16 21 M21 21 L21 16'/></svg>");
}
/* fullscreen-exit: four inward diagonals — "exit fullscreen". */
.tapp_toolbar_button[data-icon="fullscreen-exit"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M3 3 L9 9 M9 9 L4 9 M9 9 L9 4'/><path d='M21 3 L15 9 M15 9 L20 9 M15 9 L15 4'/><path d='M3 21 L9 15 M9 15 L4 15 M9 15 L9 20'/><path d='M21 21 L15 15 M15 15 L20 15 M15 15 L15 20'/></svg>");
}
.tapp_toolbar_button[data-icon="run"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23222'><path d='M13.49 5.48c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-3.6 13.9 1-4.4 2.1 2v6h2v-7.5l-2.1-2 .6-3c1.3 1.5 3.3 2.5 5.5 2.5v-2c-1.9 0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5.1-.8.1L6 8.3V13h2V9.6l1.8-.7-1.6 8.1-4.9-1-.4 2 7 1.4z'/></svg>");
}
/* reset: eraser / rubber — clears the current run results, reverting
   the chart to design mode. */
.tapp_toolbar_button[data-icon="reset"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='m7 21-4.3-4.3c-1-1-1-2.5 0-3.4l9.6-9.6c1-1 2.5-1 3.4 0l5.6 5.6c1 1 1 2.5 0 3.4L13 21'/><path d='M22 21H7'/><path d='m5 11 9 9'/></svg>");
}
/* cancel: solid stop square — the Run button morphs to this while a
   streaming run is in flight. Clicking aborts the fetch and rolls the
   UI back to design mode (see handleCancelStream in tcli.js). */
.tapp_toolbar_button[data-icon="cancel"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23222'><rect x='5' y='5' width='14' height='14' rx='2'/></svg>");
}
/* recycle: discard all overrides, return to the original model values. */
.tapp_toolbar_button[data-icon="recycle"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M7 19H4.815a1.83 1.83 0 0 1-1.57-.881 1.785 1.785 0 0 1-.004-1.784L7.196 9.5'/><path d='M11 19h8.203a1.83 1.83 0 0 0 1.556-.89 1.784 1.784 0 0 0 0-1.775l-1.226-2.12'/><path d='m14 16-3 3 3 3'/><path d='M8.293 13.596 7.196 9.5 3.1 10.598'/><path d='m9.344 5.811 1.093-1.892A1.83 1.83 0 0 1 11.985 3a1.784 1.784 0 0 1 1.546.888l3.943 6.843'/><path d='m13.378 9.633 4.096 1.098 1.097-4.096'/></svg>");
}

/* prev-slide / next-slide: slide-navigation chevrons for 3PRO. */
.tapp_toolbar_button[data-icon="prev-slide"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='15 4 7 12 15 20'/></svg>");
}
.tapp_toolbar_button[data-icon="next-slide"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='9 4 17 12 9 20'/></svg>");
}

/* Dark mode — invert SVG strokes (the inline data-URLs use a hardcoded
   stroke color; filter is the lightest way to flip both states). */
:root[tapp-theme="dark"] .tapp_toolbar_label[data-icon],
:root[tapp-theme="dark"] .tapp_toolbar_button[data-icon] {
    filter: brightness(0) invert(0.85);
}

/* ====================================================================
   Multi-select toolbar control — framework primitive (.tapp_toolbar_
   multiselect, native <details>/<summary>). Drop paints it as a
   chip pill with an anchored popover. Zero theme JS — the browser's
   native disclosure widget handles open/close. Plain HTML works
   without these rules (functional + ugly); these rules upgrade it
   to the chip aesthetic.
   ==================================================================== */
.tapp_toolbar_multiselect {
    position: relative;
    /* Pin the <details> outer box to the same 24 px row height as
       sibling toolbar items + flex its summary to the center. Without
       this, WebKit (and some Chromium builds) auto-size the <details>
       to ~36 px because they reserve vertical space for "where the
       dropdown would render" inside the box even when the options
       <div> has position: absolute and should be out of flow. The
       summary then anchors to the bottom of that oversized box and
       the toolbar's `align-items: center` flex puts the visible chip
       6 px below the button row. Diagnosed against the actual page
       in DevTools — without this rule, getBoundingClientRect on the
       <details> reports height: 36px while the inner summary is 24px.
       overflow: visible so the popover dropdown still draws outside. */
    display: inline-flex;
    align-items: center;
    height: 24px;
    overflow: visible;
}
.tapp_toolbar_multiselect[hidden] { display: none; }

/* Remove the default disclosure triangle; we paint a chevron instead. */
.tapp_toolbar_multiselect > summary {
    list-style: none;
}
.tapp_toolbar_multiselect > summary::-webkit-details-marker {
    display: none;
}

.tapp_toolbar_multiselect_summary {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    /* 24 px row height shared with toolbar buttons + select inputs
       so the toolbar reads as a slim strip. border-radius = height/2
       keeps the rounded pill end fully circular. */
    height: 24px;
    padding: 0 10px;
    /* Reset the UA-default top margin WebKit applies to <summary>
       (reserved space for the disclosure widget — still present
       even when we hide the marker). Without margin: 0, the summary's
       *margin* box (24 height + 12 top = 36px) is what flex centers
       inside the details, pushing the visible border box 6 px below
       the details center → 6 px misalignment vs sibling buttons.
       Diagnosed in DevTools: getComputedStyle(summary).marginTop
       returned "12px" before this reset. */
    margin: 0;
    background: var(--tapp_theme-surface);
    color: var(--tapp_theme-text);
    border: 1px solid var(--tapp_theme-border);
    border-radius: 12px;
    font-size: 12px;
    cursor: pointer;
    user-select: none;
    transition: background-color 120ms, border-color 120ms;
}
.tapp_toolbar_multiselect_summary:hover {
    background: var(--tapp_theme-surface-alt, rgba(0,0,0,0.04));
    border-color: var(--tapp_brand-primary);
}
.tapp_toolbar_multiselect[open] .tapp_toolbar_multiselect_summary {
    background: var(--tapp_brand-primary);
    color: var(--tapp_theme-text-inverted);
    border-color: var(--tapp_brand-primary);
}
/* Append a chevron glyph via ::after so we don't rely on the framework
   to inject a separate element. Rotates when [open]. */
.tapp_toolbar_multiselect_summary::after {
    content: "▾";
    font-size: 10px;
    line-height: 1;
    opacity: 0.6;
    transition: transform 160ms;
}
.tapp_toolbar_multiselect[open] .tapp_toolbar_multiselect_summary::after {
    transform: rotate(180deg);
    opacity: 1;
}

.tapp_toolbar_multiselect_count {
    font-variant-numeric: tabular-nums;
    opacity: 0.75;
    font-size: 11px;
}

.tapp_toolbar_multiselect_options {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    min-width: 100%;
    max-height: 320px;
    overflow-y: auto;
    z-index: 99000;
    background: var(--tapp_theme-surface);
    border: 1px solid var(--tapp_theme-border);
    border-radius: 10px;
    box-shadow: 0 8px 24px var(--tapp_theme-shadow);
    padding: 4px;
    display: block;
}

.tapp_toolbar_multiselect_option {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    border-radius: 6px;
    cursor: pointer;
    font-size: 12px;
    white-space: nowrap;
    transition: background-color 80ms;
}
.tapp_toolbar_multiselect_option:hover {
    background: var(--tapp_theme-surface-alt, rgba(0,0,0,0.04));
}
.tapp_toolbar_multiselect_option input[type="checkbox"] {
    margin: 0;
    cursor: pointer;
}
.tapp_toolbar_multiselect_option input[type="checkbox"]:disabled {
    cursor: not-allowed;
}
.tapp_toolbar_multiselect_option input[type="checkbox"]:disabled
        + .tapp_toolbar_multiselect_option_label {
    opacity: 0.6;
}
.tapp_toolbar_multiselect_option_label {
    user-select: none;
}
.tapp_toolbar_multiselect_clear {
    display: block;
    width: 100%;
    padding: 3px 10px 5px;
    text-align: right;
    font-size: 11px;
    color: var(--tapp_theme-text-dim, rgba(0,0,0,0.45));
    background: none;
    border: none;
    border-bottom: 1px solid var(--tapp_theme-border);
    cursor: pointer;
    margin-bottom: 2px;
}
.tapp_toolbar_multiselect_clear:hover {
    color: var(--tapp_theme-text);
}
@media (prefers-color-scheme: dark) {
    .tapp_toolbar_multiselect_clear {
        color: rgba(255,255,255,0.45);
    }
    .tapp_toolbar_multiselect_clear:hover { color: var(--tapp_theme-text); }
}
:root[data-theme="dark"] .tapp_toolbar_multiselect_clear {
    color: rgba(255,255,255,0.45);
}
:root[data-theme="dark"] .tapp_toolbar_multiselect_clear:hover {
    color: var(--tapp_theme-text);
}

/* ── Panel chips — foldable selection list in the detail dock ─────────────
   .tapp_panel_chips        wrapper row (hidden when selection empty)
   .tapp_panel_chips_toggle toggle button showing "N selected ▶/▼"
   .tapp_panel_chips_list   collapsible chip container
   .tapp_panel_chip         individual chip (label + ×)
   .tapp_panel_chip_label   clickable name (navigates + views)
   .tapp_panel_chip_remove  × remove button
   ────────────────────────────────────────────────────────────────────── */
.tapp_panel_chips {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 6px 16px 2px;
    border-bottom: 1px solid var(--tapp_theme-border);
    margin-bottom: 4px;
}
.tapp_panel_chips[hidden] { display: none; }
.tapp_panel_chips_toggle {
    background: none;
    border: none;
    cursor: pointer;
    font-size: 11px;
    font-weight: 600;
    color: var(--tapp_theme-text-dim, rgba(0,0,0,0.5));
    text-align: left;
    padding: 0;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}
.tapp_panel_chips_toggle::before {
    content: '▶\00a0';
    display: inline-block;
    transition: transform 120ms;
}
.tapp_panel_chips_toggle[data-open="true"]::before {
    transform: rotate(90deg);
}
.tapp_panel_chips_toggle:hover { color: var(--tapp_theme-text); }
.tapp_panel_chips_list {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    padding: 4px 0 6px;
}
.tapp_panel_chips_list[hidden] { display: none; }
.tapp_panel_chip {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    background: var(--tapp_theme-surface-alt, rgba(0,0,0,0.05));
    border: 1px solid var(--tapp_theme-border);
    border-radius: 9999px;
    padding: 2px 6px 2px 8px;
    font-size: 11px;
    max-width: 240px;
}
.tapp_panel_chip_label {
    background: none;
    border: none;
    cursor: pointer;
    font-size: inherit;
    color: var(--tapp_theme-text);
    padding: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 200px;
}
.tapp_panel_chip_label:hover { text-decoration: underline; }
.tapp_panel_chip_remove {
    background: none;
    border: none;
    cursor: pointer;
    font-size: 13px;
    line-height: 1;
    color: var(--tapp_theme-text-dim, rgba(0,0,0,0.4));
    padding: 0 0 0 2px;
    flex-shrink: 0;
}
.tapp_panel_chip_remove:hover { color: var(--tapp_theme-text); }
@media (prefers-color-scheme: dark) {
    .tapp_panel_chips_toggle { color: rgba(255,255,255,0.5); }
    .tapp_panel_chip { background: rgba(255,255,255,0.07); }
    .tapp_panel_chip_remove { color: rgba(255,255,255,0.4); }
}
:root[data-theme="dark"] .tapp_panel_chips_toggle { color: rgba(255,255,255,0.5); }
:root[data-theme="dark"] .tapp_panel_chip { background: rgba(255,255,255,0.07); }
:root[data-theme="dark"] .tapp_panel_chip_remove { color: rgba(255,255,255,0.4); }

/* Live zoom percentage between zoom-out and zoom-in buttons. Numeric,
   tabular-figures so the digits don't shift width as the value changes. */
#tcli_epi_zoom_pct {
    display: inline-block;
    min-width: 40px;
    text-align: center;
    font-size: 11px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--tapp_theme-text);
    padding: 0 4px;
}

/* Controls (search, datepicker, select, number, text) — flex container that
   lines up label + input inline. */
.tapp_toolbar > .tapp_toolbar_control {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
/* The control rule above sets display: inline-flex, which beats the
   browser's default `[hidden] { display: none }` rule (specificity
   0,2,0 > 0,1,0). Without this override, JS that does
   `el.hidden = true` on a .tapp_toolbar_control wrapper silently
   fails to hide it. Tmec-cpr's empty-state cleanup needs this so the
   Condition + Metric <select> wrappers actually disappear when no
   valid HESL is loaded. */
.tapp_toolbar > .tapp_toolbar_control[hidden] { display: none; }

/* Inputs / selects inside controls — match the pill aesthetic, fit inside
   the 26-px-button line height. */
.tapp_toolbar_input,
.tapp_toolbar_control > select.tapp_toolbar_input {
    height: 24px;
    padding: 0 10px;
    background: var(--tapp_theme-surface-alt);
    color: var(--tapp_theme-text);
    border: 1px solid var(--tapp_theme-border);
    border-radius: 12px;
    font: 12px/1 inherit;
    outline: none;
    transition: border-color 160ms, box-shadow 160ms;
}
.tapp_toolbar_input::placeholder {
    color: var(--tapp_theme-text-muted);
}
.tapp_toolbar_input:focus {
    border-color: var(--tapp_brand-secondary);
    box-shadow: 0 0 0 2px var(--drop-curve-tint);
}
/* Sensible default widths per kind. */
.tapp_toolbar_control-search  > .tapp_toolbar_input { min-width: 220px; }
.tapp_toolbar_control-datepicker > .tapp_toolbar_input { min-width: 130px; }
.tapp_toolbar_control-number  > .tapp_toolbar_input { width: 80px; }
.tapp_toolbar_control-text    > .tapp_toolbar_input { min-width: 160px; }
.tapp_toolbar_control-select  > .tapp_toolbar_input { padding-right: 24px; }

/* Separator — vertical divider between groups. Subtle but visible on
   the frosted-glass toolbar pill in both light and dark modes. */
.tapp_toolbar > .tapp_toolbar_separator {
    display: inline-block;
    width: 1px;
    height: 18px;
    background-color: currentColor;
    opacity: 0.25;
    margin: 0 6px;
}

/* Action group — keeps multiple buttons tight together. */
.tapp_toolbar > .tapp_toolbar_actions {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

/* Sidebar — full-height brand-coloured pill outside the card. Holds the
   toggle, the section circle-buttons, a flex spacer, and the vertical
   title (moved <h2>) at the bottom. Collapsed: 40px wide; expanded (via
   the toggle): 200px. */
#tapp_workspace > section.tapp_feature_section > nav.tapp_feature_nav {
    grid-column: 1;
    align-self: stretch;
    width: 40px;
    /* visible (not hidden) so floating section labels can render outside
       the sidebar pill, in the gap that opens up when expanded. */
    overflow: visible;
    background: var(--tapp_brand-primary);
    color: var(--tapp_theme-text-inverted);
    border: 0;
    box-shadow: 0 6px 18px var(--tapp_theme-shadow);
    border-radius: 20px;
    padding: 6px 4px;
    display: flex;
    flex-direction: column;
}

/* Toggle — circle, white-tint on the brand sidebar; flips to solid white
   with brand text on hover. Pinned to the left so it stays in place when
   the sidebar widens (rather than gliding to center). */
.drop_nav_toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    align-self: flex-start;
    width: 32px;
    height: 32px;
    margin: 0 0 6px;
    padding: 0;
    background: rgba(255, 255, 255, 0.18);
    border: 0;
    color: var(--tapp_theme-text-inverted);
    border-radius: 50%;
    cursor: pointer;
    transition: background-color 160ms, color 160ms;
}
.drop_nav_toggle:hover {
    background: var(--tapp_theme-text-inverted);
    color: var(--tapp_brand-primary);
}
.drop_nav_toggle_icon {
    width: 14px;
    height: 14px;
    transition: transform 220ms var(--drop-ease-soft);
}
#tapp_workspace > section.tapp_feature_section > nav.tapp_feature_nav[data-tapp-nav-expanded="true"] .drop_nav_toggle_icon {
    transform: rotate(180deg);
}

#tapp_workspace > section.tapp_feature_section > nav.tapp_feature_nav .tapp_menu {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}
#tapp_workspace > section.tapp_feature_section > nav.tapp_feature_nav .tapp_menu_item {
    margin: 0;
}

/* Title pill — the framework's <h2> moved into the nav as the top item.
   Always visible; vertical orientation so the pill stays narrow and fits
   the collapsed sidebar without horizontal clipping. writing-mode:
   vertical-rl + transform: rotate(180deg) makes Latin text read
   bottom-to-top against the spine. */
.drop_nav_title {
    margin: 0 0 10px;
    padding: 14px 6px;
    align-self: flex-start;
    background: rgba(255, 255, 255, 0.18);
    color: var(--tapp_theme-text-inverted);
    border-radius: 16px;
    font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display", "Helvetica Neue", Arial, sans-serif;
    font-weight: 700;
    font-size: 12px;
    letter-spacing: 0.02em;
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    user-select: none;
    max-height: 60%;
}
/* The framework adds a small tier badge inside the h2; keep it readable
   against the brand background. */
.drop_nav_title .tapp_tier_badge {
    background: rgba(255, 255, 255, 0.22);
    color: var(--tapp_theme-text-inverted);
}

/* Button is a transparent click row — the visible "button" is the icon
   circle inside. The label is absolute-positioned outside the sidebar
   so it can float in the gap that opens up when the sidebar expands. */
#tapp_workspace > section.tapp_feature_section > nav.tapp_feature_nav .tapp_menu_btn[data-target] {
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    height: 32px;
    padding: 0;
    background: transparent;
    border: 0;
    color: var(--tapp_theme-text);
    cursor: pointer;
    text-align: left;
    font: inherit;
}

/* The icon circle — white-tinted on the brand sidebar when inactive,
   solid white with brand-colored glyph on hover/active. */
.drop_section_icon {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.18);
    color: var(--tapp_theme-text-inverted);
    font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display", "Helvetica Neue", Arial, sans-serif;
    font-weight: 700;
    font-size: 13px;
    transition: background-color 160ms, color 160ms;
}
.drop_section_icon svg {
    width: 16px;
    height: 16px;
}
/* Hover/active applies to the whole row (the click target) but only
   colorizes the circle. */
#tapp_workspace > section.tapp_feature_section > nav.tapp_feature_nav .tapp_menu_btn[data-target]:hover .drop_section_icon,
#tapp_workspace > section.tapp_feature_section > nav.tapp_feature_nav .tapp_menu_btn[data-target][aria-current="page"] .drop_section_icon {
    background: var(--tapp_theme-text-inverted);
    color: var(--tapp_brand-primary);
}

/* Label floats OUTSIDE the sidebar in the gap between the pill and the
   body card. Absolute-positioned past the icon's right edge; visible only
   when the sidebar is in the expanded state. */
.drop_section_label {
    position: absolute;
    left: calc(100% + 14px);
    top: 50%;
    transform: translateY(-50%);
    padding: 4px 10px;
    background: var(--tapp_theme-surface);
    color: var(--tapp_theme-text);
    border-radius: 12px;
    box-shadow: 0 4px 12px var(--tapp_theme-shadow);
    font-size: 12px;
    line-height: 1.2;
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    transition: opacity 200ms var(--drop-ease-soft);
}
#tapp_workspace > section.tapp_feature_section > nav.tapp_feature_nav[data-tapp-nav-expanded="true"] .drop_section_label {
    opacity: 1;
    pointer-events: auto;
}

/* Body card — every direct child that's NOT the brand h2, the nav, or
   one of our section-cycle arrow buttons fills column 2. Full rounded
   corners now that the brand strip is gone (the title lives vertically
   inside the brand-coloured nav). */
/* The framework's createSection injects an <h3 class="tapp_section_heading">
 * at the top of every subsection (e.g. "Browse" / "Buscar"). Drop hides
 * it: the module/feature identifier lives in the sidebar (vertical title
 * pill), and the section-arrows pill at top-right indicates which subsection
 * is active. The h3 was visual redundancy and pushed the toolbar pill down
 * out of the corner. */
#tapp_workspace > section.tapp_feature_section .tapp_section_heading {
    display: none;
}
/* …but a NESTED sub-section's heading inside the workspace area
   stays visible AND gets Drop's brand-tinted uppercase band. This
   is Drop's painting of the FRAMEWORK sub-section primitive —
   TApp.createSection emits <section class="tapp_section">
   <h3 class="tapp_section_heading">…</h3></section>, and themes
   (Drop here, Classic + others elsewhere) paint that primitive
   however they choose. Selector specificity 1,4,1 beats the hide
   rule's 1,2,1, so the heading reveals and the band styling lands.
   tcli-epi keeps its own rule below (predates this primitive). */
#tapp_workspace > section.tapp_feature_section .tapp_section .tapp_section .tapp_section_heading {
    display:        block;
    margin:         12px 0 6px;
    padding:        4px 10px;
    background:     color-mix(in srgb, var(--tapp_brand-primary) 10%, transparent);
    border-radius:  4px;
    font-family:    ui-sans-serif, system-ui, sans-serif;
    font-size:      12px;
    font-weight:    600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color:          var(--tapp_theme-text-muted);
}

#tapp_workspace > section.tapp_feature_section > *:not(h2):not(nav):not(.drop_section_arrows_pill):not(.tapp_toolbar) {
    grid-column: 2;
    align-self: stretch;
    min-width: 0;
    background: var(--drop-topbar-bg);
    backdrop-filter: saturate(160%) blur(20px);
    -webkit-backdrop-filter: saturate(160%) blur(20px);
    /* Border thickness AND color match the pill trenches — so where a pill
       (toolbar / section-arrows) bites a corner, the card's border and the
       pill's trench read as ONE continuous trench wrapping the whole card.
       The pill bites are now flush on every side they touch, not just on
       top. The 4 px width also gives the card itself a "carved into the
       canvas" feel consistent with the pill aesthetic. */
    border: 4px solid var(--tapp_theme-background);
    border-radius: 18px;
    /* drop shadow + a hairline gray inset border (sits inside the 4px
       trench so the card reads as bounded but the carved look is kept). */
    box-shadow:
        0 12px 40px var(--tapp_theme-shadow),
        inset 0 0 0 1px var(--tapp_theme-border);
    padding: 20px 24px;
    /* overflow: visible (not auto) so the absolutely-positioned toolbar can
       overlap the card's border on the top + left; otherwise the negative
       offsets get clipped at the padding-box. Long table content can scroll
       at the page level instead of inside the card. */
    overflow: visible;
    /* Positioning context for the absolutely-positioned toolbar pill. */
    position: relative;
}
/* When the body card contains a toolbar, reserve top space so the
   table / content below isn't covered by the absolute pill. */
#tapp_workspace > section.tapp_feature_section > *:not(h2):not(nav):not(.drop_section_arrows_pill):not(.tapp_toolbar):has(.tapp_toolbar) {
    padding-top: 60px;
}

/* Tier badge inside the framework header reads against the brand strip. */
#tapp_workspace > section.tapp_feature_section > h2:first-child .tapp_tier_badge {
    color: var(--tapp_theme-text-inverted);
    background: rgba(255, 255, 255, 0.2);
}

/* Defensive: hide the landing whenever a feature panel is visible. The
   framework already sets `landing.hidden = true` on activateFeature, but
   this rule guarantees the right state regardless of order or timing —
   landing only appears when no feature is mounted and visible. */
#tapp_workspace:has(> section.tapp_feature_section:not([hidden])) #tapp_landing {
    display: none;
}

#tapp_landing {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    text-align: center;
}
#tapp_landing[hidden] { display: none; }

#tapp_landing_tagline {
    margin: 0;
    color: var(--tapp_theme-text);
    font-weight: 600;
    font-size: 18px;
}
#tapp_landing_description {
    margin: 0;
    max-width: min(640px, calc(100vw - 32px));
    color: var(--tapp_theme-text-muted);
    font-size: 14px;
}

/* ============================================
   Landing actions — the "Start" walkthrough CTA plus the row of
   model-dimension launchers, both populated from
   <teff:app id="tapp">/<teff:gen>/{walkthrough,dimensions}.
   The container hides itself when neither is present (populateLandingActions
   toggles [hidden]); each child hides independently.
   ============================================ */

#tapp_landing_actions {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    margin-top: 4px;
}
#tapp_landing_actions[hidden] { display: none; }

#tapp_landing_start {
    padding: 9px 28px;
    background: var(--tapp_brand-primary);
    color: var(--tapp_theme-text-inverted);
    border: none;
    border-radius: 999px;
    font-size: 15px;
    font-weight: 600;
    cursor: pointer;
    box-shadow: 0 2px 8px color-mix(in srgb, var(--tapp_brand-primary) 35%, transparent);
    transition: filter 0.15s ease, box-shadow 0.15s ease;
}
#tapp_landing_start:hover {
    filter: brightness(1.08);
    box-shadow: 0 4px 12px color-mix(in srgb, var(--tapp_brand-primary) 45%, transparent);
}
#tapp_landing_start[hidden] { display: none; }

.tapp_landing_dimensions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px;
    max-width: min(640px, calc(100vw - 32px));
}
.tapp_landing_dimension {
    padding: 6px 16px;
    background: transparent;
    color: var(--tapp_brand-primary);
    border: 1px solid color-mix(in srgb, var(--tapp_brand-primary) 45%, transparent);
    border-radius: 999px;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.tapp_landing_dimension:hover {
    background: var(--tapp_brand-primary);
    color: var(--tapp_theme-text-inverted);
    border-color: var(--tapp_brand-primary);
}

/* ============================================
   Centered landing logo — Drop paints the framework's plain-HTML
   #tapp_landing_logo slot directly. No JS injection.
   ============================================ */

#tapp_landing_logo {
    width: var(--drop-logo-landing);
    height: var(--drop-logo-landing);
}
#tapp_landing_logo img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

/* HESL-provided brand logo via <teff:gen>/<teff:logo>. Two modes,
   stamped on the slot as data-tapp-logo-mode by populateLandingLogo:

   replace — brand fully takes over the square slot. JS hides the
             default 3app img; the brand SVG fills the slot via
             100% sizing + object-fit:contain so any aspect ratio
             stays inside the square (no clipping).

   beside  — both logos visible, laid out as a horizontal row. The
             slot gives up its fixed square width and grows
             horizontally instead, so a wordmark-style brand logo
             (170×40-ish) sits cleanly next to the 3app mark
             without being squashed. Each child gets full height /
             auto width so aspect ratios are preserved. */
#tapp_landing_logo[data-tapp-logo-mode="replace"] > [data-tapp-brand-logo] {
    width:      100%;
    height:     100%;
    object-fit: contain;
}

/* Size axis — applies only to position="replace" (beside mode sizes
   itself from intrinsic content dimensions). populateLandingLogo
   stamps data-tapp-logo-size="big" | "mid" | "small" on the slot;
   "mid" is the default.

   All three hug the art: each picks the largest size fitting BOTH a
   width cap and a height budget, using the logo's own aspect ratio to
   trade one for the other. populateLandingLogo stamps --tapp-logo-aspect
   (= viewBox width / height) on the slot; the same value drives
   aspect-ratio AND the height-budget term in the width calc — a wide
   logo's width = <budget> × aspect (capped) so it spreads horizontally,
   while a square/tall logo is bounded by the height budget. A square
   logo therefore renders exactly <budget> square, preserving the old
   360 / 280 / 200 baselines. 1/1 fallback keeps it square if the var is
   absent. The per-size pair is (width cap / vw cap, height budget). */
#tapp_landing_logo[data-tapp-logo-mode="replace"][data-tapp-logo-size="big"] {
    width:  min(720px, 80vw, calc(360px * var(--tapp-logo-aspect, 1)));
    height: auto;
    aspect-ratio: var(--tapp-logo-aspect, 1 / 1);
}
#tapp_landing_logo[data-tapp-logo-mode="replace"][data-tapp-logo-size="mid"] {
    width:  min(560px, 70vw, calc(280px * var(--tapp-logo-aspect, 1)));
    height: auto;
    aspect-ratio: var(--tapp-logo-aspect, 1 / 1);
}
#tapp_landing_logo[data-tapp-logo-mode="replace"][data-tapp-logo-size="small"] {
    width:  min(400px, 60vw, calc(200px * var(--tapp-logo-aspect, 1)));
    height: auto;
    aspect-ratio: var(--tapp-logo-aspect, 1 / 1);
}
#tapp_landing_logo[data-tapp-logo-mode="beside"] {
    display:        inline-flex;
    flex-direction: row;
    align-items:    center;
    justify-content: center;
    gap:            16px;
    width:          auto;       /* let the row size to its children */
    max-width:      90vw;
}
#tapp_landing_logo[data-tapp-logo-mode="beside"] img,
#tapp_landing_logo[data-tapp-logo-mode="beside"] > [data-tapp-brand-logo] {
    height:     100%;
    width:      auto;
    max-width:  none;
    object-fit: contain;
}

/* ============================================
   Drop bell hanging from the top edge
   A small SVG with a goo / metaball filter merges a hidden "ceiling" patch
   with the visible bell circle. At rest, the bell silhouette merges into the
   ceiling — looks like a forming drop. On hover, the bell drops, a stretched
   neck connects it to the ceiling. On click, the bell descends past the goo
   threshold and separates: a free-floating circle with a glowing "3".
   ============================================ */

.drop_curve {
    position: fixed;
    top: 0;
    left: 50%;
    width: 200px;
    height: 280px;
    transform: translateX(-50%);
    z-index: 50;
    pointer-events: none;
    overflow: visible;       /* let the patch widen past the SVG box on active */
}

.drop_curve_silhouette { fill: var(--tapp_brand-primary); }

.drop_curve_drop,
.drop_curve_drop_3 {
    transform-box: fill-box;
    transform-origin: center;
}

/* Gaussian patch — anchored to the TOP so it stays glued to the ceiling
   throughout the animation. On active it widens AND flattens upward (scaleY
   pulls the bottom up toward the top), so the path looks like water flowing
   up and outward into the ceiling, then fading. */
.drop_curve_patch {
    transform-box: fill-box;
    transform-origin: 50% 0%;
    transform: scaleX(1) scaleY(1);
    opacity: 1;
    /* Asymmetric timing: the transition properties on the destination state
       apply, so faster values here drive deactivation (active → rest). */
    transition:
        transform 380ms var(--drop-ease-soft),
        opacity 300ms var(--drop-ease-soft);
}
html[data-tapp-launcher="active"] .drop_curve_patch {
    transform: scaleX(4) scaleY(0.15);
    opacity: 0;
    /* Slow & deliberate on activation so the widen/flatten reads. */
    transition:
        transform 1400ms var(--drop-ease-soft),
        opacity 1200ms var(--drop-ease-soft) 200ms;
}

/* Bell and the "3" each get their own active transform so the "3" lands
   centered on the bell when active (the "3" needs less translateY because
   its rest position is already 18px below the bell center).
   At rest and peeked, both stay put — peeked only brightens the "3". */
.drop_curve_drop,
.drop_curve_drop_3 {
    transform: translateY(0) scale(1);
    /* Deactivation: smooth, no overshoot — the bell shouldn't bounce as it
       returns to the ceiling. */
    transition: transform 480ms var(--drop-ease-soft);
}
html[data-tapp-launcher="active"] .drop_curve_drop {
    transform: translateY(var(--drop-bell-active)) scale(var(--drop-bell-active-scale));
    /* Activation: spring keeps the satisfying "drop & settle" feel. */
    transition: transform 720ms var(--drop-ease-spring);
}
html[data-tapp-launcher="active"] .drop_curve_drop_3 {
    transform: translateY(var(--drop-image-active)) scale(var(--drop-image-active-scale));
    transition: transform 720ms var(--drop-ease-spring);
}

/* "3" image — always visible (this is a 3-app portal). Dimmed at rest,
   subtle glow on peeked, bright glow on active. */
.drop_curve_3_image {
    opacity: 0.55;
    transition:
        opacity 360ms var(--drop-ease-soft),
        filter 360ms var(--drop-ease-soft);
}
html[data-tapp-launcher="peeked"] .drop_curve_3_image {
    opacity: 0.85;
    filter:
        drop-shadow(0 0 4px rgba(255, 255, 255, 0.35))
        drop-shadow(0 0 8px rgba(95, 166, 227, 0.4));
}
html[data-tapp-launcher="active"] .drop_curve_3_image {
    opacity: 1;
    transition-delay: 120ms; /* let the bell start descending before the 3 lights up */
    filter:
        drop-shadow(0 0 6px rgba(255, 255, 255, 0.7))
        drop-shadow(0 0 18px rgba(95, 166, 227, 0.85));
}

/* Hit area — wraps the bell silhouette.
   REST: small (80×28) covers only the visible sliver-peek at the
   viewport's top edge, so toolbar items behind/around the drop in
   feature sections remain clickable.
   PEEKED: expands to follow the descended bell + image (200×80),
   matching the previous always-on hit area now that the user has
   committed to interacting with the launcher (hover).
   ACTIVE: same expanded box, translated down to follow the "3"
   image so clicking the visible "3" closes the launcher (the
   backdrop handles outside-clicks for the rest). */
.drop_curve_hit {
    position: fixed;
    top: 0; left: 50%;
    width: 80px;
    height: 28px;
    transform: translateX(-50%) translateY(0);
    z-index: 70;
    cursor: pointer;
    background: transparent;
    border: 0;
    padding: 0;
    transition: width 240ms var(--drop-ease-soft),
                height 240ms var(--drop-ease-soft),
                transform 480ms var(--drop-ease-soft);
}
html[data-tapp-launcher="peeked"] .drop_curve_hit {
    width: 200px;
    height: 80px;
}
html[data-tapp-launcher="active"] .drop_curve_hit {
    width: 200px;
    height: 80px;
    transform: translateX(-50%) translateY(var(--drop-image-active));
    transition: transform 720ms var(--drop-ease-spring);
}

/* ============================================
   Spotlight panel (drops from top edge, anchored under the curve)
   ============================================ */

.drop_spotlight {
    position: fixed;
    top: 0; left: 50%;
    transform: translate(-50%, -120%);
    width: min(720px, calc(100vw - 32px));
    background: var(--tapp_theme-surface);
    border-radius: 18px;
    box-shadow:
        0 24px 56px var(--tapp_theme-shadow),
        0 2px 8px rgba(15, 59, 130, 0.06);
    z-index: 75;
    opacity: 0;
    padding: 22px 0 14px;
    max-height: min(80vh, 640px);
    display: flex;
    flex-direction: column;
    transition:
        transform 480ms var(--drop-ease-spring),
        opacity 280ms var(--drop-ease-soft);
}

html[data-tapp-launcher="active"] .drop_spotlight {
    transform: translate(-50%, var(--drop-spotlight-top));
    opacity: 1;
}

/* Search row */
.drop_spotlight_search {
    margin: 0 22px 14px;
    position: relative;
}
.drop_spotlight_search input {
    width: 100%;
    height: 44px;
    padding: 0 16px 0 44px;
    border: 1px solid var(--tapp_theme-border);
    border-radius: 10px;
    background: var(--tapp_theme-surface);
    color: var(--tapp_theme-text);
    font-size: 15px;
    outline: none;
    font-family: inherit;
    transition: border-color 120ms, box-shadow 120ms;
}
.drop_spotlight_search input:focus {
    border-color: var(--tapp_brand-secondary);
    box-shadow: 0 0 0 3px rgba(78, 149, 210, 0.18);
}
.drop_spotlight_search::before {
    content: "";
    position: absolute;
    left: 14px; top: 50%;
    width: 18px; height: 18px;
    transform: translateY(-50%);
    background: no-repeat center/contain url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23919191' stroke-width='2.2' stroke-linecap='round'><circle cx='11' cy='11' r='7'/><path d='m21 21-4.3-4.3'/></svg>");
    pointer-events: none;
}

.drop_spotlight_section_title {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--tapp_theme-text-muted);
    padding: 4px 24px 8px;
}

/* Slot that hosts the moved #tapp_nav_modules */
.drop_spotlight_modules_slot {
    overflow-y: auto;
    padding: 0 12px 8px;
    flex: 1;
}

/* ============================================
   Module list (moved from #tapp_header into the spotlight)
   These rules apply only while drop is the active theme — the file
   is loaded only then.
   ============================================ */

#tapp_nav_modules {
    display: block;
}

.tapp_nav_heading { display: none; }

/* In Drop, the spotlight uses flex-wrap so pills are exactly 40px while
   tiles grow to fill space. The original nested DOM is preserved:
     module <li> → display:contents (pill button becomes flex item)
     .tapp_submenu → display:contents !important (overrides [hidden]; feature <li>s become flex items)
   No JS DOM restructuring needed. */
#tapp_modules {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    row-gap: 8px;
    column-gap: 0;
}

/* Module <li> transparent to layout — no !important so JS can hide via style.display. */
#tapp_modules > li.tapp_menu_item {
    display: contents;
    list-style: none;
    margin: 0;
    padding: 0;
}

/* Submenu transparent to layout — !important overrides [hidden]. */
#tapp_modules .tapp_submenu {
    display: contents !important;
    list-style: none;
    margin: 0;
    padding: 0;
}

/* Pill button — direct flex item (via display:contents on module <li>). Exactly 40px. */
#tapp_modules > li > button[data-module] {
    flex: 0 0 40px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;
    min-height: 84px;
    padding: 10px 4px;
    border: 0;
    border-radius: 10px;
    background: color-mix(in srgb, var(--tapp_brand-primary) 12%, transparent);
    color: var(--tapp_theme-text-muted);
    font-family: inherit;
    pointer-events: none;
    cursor: default;
}
#tapp_modules > li > button[data-module] .tapp_menu_icon { font-size: 13px; line-height: 1; }
#tapp_modules > li > button[data-module] .tapp_menu_label {
    font-weight: 700;
    font-size: 9px;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    line-height: 1;
    writing-mode: vertical-rl;
    transform: rotate(180deg);
}

/* Feature <li> — direct flex item (via display:contents on submenu). */
#tapp_modules .tapp_submenu > li.tapp_menu_item {
    flex: 1 0 0;
    min-width: 80px;
    max-width: 160px;   /* cap growth so incomplete rows don't stretch tiles */
    position: relative;
    margin-left: 8px;   /* gap between tiles */
}
/* First feature of each module sits flush against its pill — no left gap. */
#tapp_modules .tapp_submenu > li.tapp_menu_item:first-child {
    margin-left: 0;
}

/* Feature tile button. */
#tapp_modules .tapp_submenu .tapp_menu_btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: 100%;
    min-height: 84px;
    padding: 12px 8px;
    border: 0;
    background: rgba(78, 149, 210, 0.05);
    color: var(--tapp_theme-text);
    font-size: 12px;
    font-family: inherit;
    text-align: center;
    border-radius: 12px;
    cursor: pointer;
    transition: background-color 160ms, color 160ms, transform 120ms;
}
#tapp_modules .tapp_submenu .tapp_menu_btn:hover,
#tapp_modules .tapp_submenu .tapp_menu_btn.active {
    background: rgba(78, 149, 210, 0.15);
    color: var(--tapp_brand-primary);
    transform: translateY(-1px);
}
#tapp_modules .tapp_submenu .tapp_menu_icon { font-size: 28px; line-height: 1; }
#tapp_modules .tapp_submenu .tapp_menu_label {
    font-weight: 500;
    font-size: 12px;
    line-height: 1.2;
    word-break: break-word;
}


/* ============================================
   Login dialog — adapted from 3eff theme
   ============================================ */

.tapp_dialog {
    border: 1px solid var(--tapp_theme-border);
    border-radius: 8px;
    padding: 20px;
    max-width: 400px;
    box-shadow: 0 8px 24px var(--tapp_theme-shadow);
    background: var(--tapp_theme-surface);
    color: var(--tapp_theme-text);
    font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", Arial, sans-serif;
}
.tapp_dialog::backdrop {
    background: rgba(0, 0, 0, 0.35);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}

/* ── Dialog helper primitives ────────────────────────────────────────────
   tapp_dialog_formats   format radio row (CSV / Excel / PDF)
   tapp_dialog_section   collapsible options block (PDF layout, etc.)
   tapp_dialog_footer    action button row
   tapp_btn              standalone action button (outside toolbar / header)
   tapp_btn-primary      primary variant
   ──────────────────────────────────────────────────────────────────────── */
.tapp_dialog h3 {
    margin: 0 0 16px;
    font-size: 1.05em;
    color: var(--tapp_theme-text);
}
.tapp_dialog_formats {
    display: flex;
    gap: 20px;
    font-size: .9em;
}
.tapp_dialog_formats label {
    display: flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
}
.tapp_dialog_section {
    display: flex;
    flex-direction: column;
    gap: 10px;
    font-size: .9em;
    border-top: 1px solid var(--tapp_theme-border);
    margin-top: 16px;
    padding-top: 14px;
}
.tapp_dialog_section[hidden] { display: none; }
.tapp_dialog_section label {
    display: flex;
    align-items: center;
    gap: 8px;
}
.tapp_dialog_section select {
    margin-left: auto;
    padding: 3px 6px;
    background: var(--tapp_theme-surface);
    color: var(--tapp_theme-text);
    border: 1px solid var(--tapp_theme-border);
    border-radius: 4px;
}
/* nav.tapp_dialog_footer sits after dialog content; only adds top spacing —
   the button paint comes from .tapp_dialog nav ul button above. */
nav.tapp_dialog_footer { margin-top: 20px; }

/* Standalone action buttons — used outside toolbar/header contexts
   (e.g. import panel subsections, preview action rows). Pill style
   matching the dialog button aesthetic. */
.tapp_btn {
    padding: 5px 14px;
    background: var(--tapp_theme-surface-alt);
    color: var(--tapp_theme-text);
    border: 1px solid var(--tapp_theme-border);
    border-radius: 9999px;
    cursor: pointer;
    font: inherit;
    font-size: 0.8125rem;
    white-space: nowrap;
    transition: background-color 120ms, border-color 120ms;
}
.tapp_btn:hover:not(:disabled) {
    background: var(--drop-topbar-hover);
    border-color: var(--tapp_brand-secondary);
}
.tapp_btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}
.tapp_btn-primary {
    background: var(--tapp_brand-secondary);
    color: var(--tapp_theme-text-inverted);
    border-color: var(--tapp_brand-secondary);
}
.tapp_btn-primary:hover:not(:disabled) {
    background: var(--tapp_theme-link-hover);
    border-color: var(--tapp_theme-link-hover);
}
/* File-select trigger — replace text with folder-open glyph. */
.tapp_btn[tapp-i18n="tmgm_text_selectFile"] {
    font-size: 0;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background-color: transparent;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v1'/><path d='M21 19H3l2-9h16l-2 9z'/></svg>");
    background-repeat: no-repeat;
    background-position: center;
    background-size: 18px 18px;
}
.tapp_btn[tapp-i18n="tmgm_text_selectFile"]:hover:not(:disabled) {
    background-color: var(--drop-topbar-hover);
    border-color: transparent;
}
:root[tapp-theme="dark"] .tapp_btn[tapp-i18n="tmgm_text_selectFile"] {
    filter: brightness(0) invert(0.85);
}

/* ── Import-panel layout primitives ─────────────────────────────────────────
   tapp_import_row   flex row for file-select controls (button + name + action)
   tapp_form_row     flex row for labelled form inputs (wraps on small screens)
   tapp_file_name    filename display span — muted, truncated, fills remaining space
   tapp_label_hint   small muted label above a file input in a dual-import row
   tapp_input_xs     narrow input (e.g. 3-char currency code)
   tapp_input_sm     medium input (e.g. rate, source text)
   tapp_loading      inline loading message container
   tapp_spinner      CSS-animated spinner element inside tapp_loading
   tapp_chart_wrap   embedded chart container (border + min-height)
   tapp_stat_row     horizontal summary-count row above import sections
   tapp_scroll_wrap  horizontal-scroll wrapper for wide tables
   tapp_page_row     pagination control row
   tapp_page_info    "N–M / total" label inside pagination row
   tapp_empty_msg    centred empty / no-results paragraph
   [data-mt]         one-rem top-margin spacer for appended section cards      */

.tapp_import_row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0;
    min-height: 3rem;
    flex-wrap: wrap;
}
.tapp_form_row {
    display: flex;
    align-items: flex-end;
    gap: 0.75rem;
    flex-wrap: wrap;
    padding: 0.5rem 0;
}
.tapp_file_name {
    color: var(--tapp_theme-text-muted);
    font-size: 0.8125rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    flex: 1;
}
.tapp_label_hint {
    font-size: 0.75rem;
    color: var(--tapp_theme-text-muted);
    white-space: nowrap;
}
.tapp_input_xs { width: 4.5rem; }
.tapp_input_sm { width: 8rem; }

@keyframes tapp-spin { to { transform: rotate(360deg); } }
.tapp_loading {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0;
    color: var(--tapp_theme-text-muted);
    font-size: 0.875rem;
}
.tapp_spinner {
    display: inline-block;
    width: 14px;
    height: 14px;
    border: 2px solid var(--tapp_theme-border);
    border-top-color: var(--tapp_brand-primary);
    border-radius: 50%;
    animation: tapp-spin 0.7s linear infinite;
    flex-shrink: 0;
}
.tapp_chart_wrap {
    min-height: 160px;
    border: 1px solid var(--tapp_theme-border);
    border-radius: 6px;
    padding: 0.5rem;
    margin-top: 0.5rem;
}
.tapp_stat_row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1.25rem;
    align-items: center;
    padding: 0.5rem 0;
    font-size: 0.875rem;
}
.tapp_scroll_wrap {
    overflow-x: auto;
    width: 100%;
}
.tapp_scroll_wrap .tapp_table {
    width: 100%;
    border-collapse: collapse;
}
.tapp_page_row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0;
}
.tapp_page_info {
    font-size: 0.8125rem;
    color: var(--tapp_theme-text-muted);
}
.tapp_empty_msg {
    padding: 1rem;
    text-align: center;
    color: var(--tapp_theme-text-muted);
    font-size: 0.8125rem;
    margin: 0;
}
[data-mt] { margin-top: 1rem; }

/* Module content scroll panel — wraps feature panel content. */
.tapp_content {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 0.75rem;
}
/* Zero-size spacer that maintains toolbar pill height in label-only toolbars. */
.tapp_toolbar_spacer {
    display: inline-block;
    width: 0;
    height: 32px;
}
/* D3 axis group — path/tick/text theming. */
.tapp_axis path.domain,
.tapp_axis .tick line { stroke: var(--tapp_theme-text-muted); }
.tapp_axis .tick text  { fill:   var(--tapp_theme-text-muted); }

/* Opt-in wide dialog (TApp.dialog.modal({ wide:true })) — for rich content
   like the endpoint comparison table + chart. Overrides the 400px cap. */
.tapp_dialog[data-wide] {
    max-width: 90vw;
    min-width: 50vw;
}

/* Profile + Help dialogs — fixed viewport-relative size, set in CSS so the
   dialog doesn't resize as async content loads. */
.tapp_dialog:has(.tapp_profile_dialog_panel) {
    width:     min(720px, 92vw);
    max-width: min(720px, 92vw);
    min-width: unset;
}
.tapp_dialog:has(.tapp_help_dialog) {
    width:     min(800px, 94vw);
    max-width: min(800px, 94vw);
    min-width: unset;
}

/* Edit dialogs (those holding number inputs) size to their CONTENT rather than
   the 400px cap — so a long pack name + value/unit stay on one line without a
   forced-wide (50vw) min. Capped at 90vw; grows only as far as needed.
   Excluded when the dialog contains a .tapp_pricing_tab (file-settings modal),
   which is intentionally wide and should not shrink to fit-content. */
.tapp_dialog:not(:has(.tapp_pricing_tab)):has(.tapp_table input[type="number"]) {
    width:     fit-content;
    max-width: 90vw;
    min-width: auto;
}

/* Inline confidence-interval line under a response rate (second line of the
   merged "Response rate" cell). Muted + smaller so the rate stays dominant. */
.tapp_ci {
    font-size: 0.85em;
    opacity: 0.7;
}

/* Provenance / source annotation — tertiary line below a value and its CI.
   Lighter and smaller than .tapp_ci so the visual hierarchy is unambiguous:
   primary value → CI (analytical) → provenance (source). */
.tapp_provenance {
    font-size: 0.75em;
    opacity: 0.55;
}

.tapp_dialog:has(#tapp_login_logo) {
    max-width: 360px;
    padding: 32px 32px 24px;
    text-align: center;
    border-top: 3px solid var(--tapp_brand-secondary);
}

#tapp_login_logo {
    margin-bottom: 20px;
}
#tapp_login_logo p {
    font-size: 0;
    width: 160px;
    height: 48px;
    margin: 0 auto;
    background: url('../../../../images/3app-logo.png') no-repeat center center;
    background-size: contain;
}
:root[tapp-theme="dark"] #tapp_login_logo p {
    background-image: url('../../../../images/3app-logo-white.png');
}

.tapp_login_error {
    color: var(--tapp_status-error);
    font-size: 13px;
    margin: 0 0 12px;
    padding: 8px;
    background: var(--tapp_status-error-light);
    border-radius: 4px;
}

.tapp_login_providers ul {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.tapp_login_provider {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 10px 16px;
    border: 1px solid var(--tapp_theme-border);
    border-radius: 6px;
    text-decoration: none;
    color: var(--tapp_theme-text);
    font-size: 14px;
    font-weight: 500;
    background: var(--tapp_theme-surface);
    transition: background 150ms, box-shadow 150ms;
}
.tapp_login_provider:hover {
    background: var(--tapp_theme-surface-alt);
    box-shadow: 0 1px 3px var(--tapp_theme-shadow);
}

.tapp_login_provider_icon {
    display: inline-block;
    width: 20px;
    height: 20px;
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    flex-shrink: 0;
}
[data-provider="google"] .tapp_login_provider_icon {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'%3E%3Cpath fill='%23EA4335' d='M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z'/%3E%3Cpath fill='%234285F4' d='M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z'/%3E%3Cpath fill='%2334A853' d='M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z'/%3E%3Cpath fill='%23FBBC05' d='M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z'/%3E%3C/svg%3E");
}
[data-provider="microsoft"] .tapp_login_provider_icon {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 21 21'%3E%3Crect x='1' y='1' width='9' height='9' fill='%23f25022'/%3E%3Crect x='1' y='11' width='9' height='9' fill='%2300a4ef'/%3E%3Crect x='11' y='1' width='9' height='9' fill='%237fba00'/%3E%3Crect x='11' y='11' width='9' height='9' fill='%23ffb900'/%3E%3C/svg%3E");
}

.tapp_login_lang {
    margin-top: 20px;
    font-size: 12px;
    color: var(--tapp_theme-text-muted);
}
.tapp_login_lang select {
    background: var(--tapp_theme-surface);
    color: var(--tapp_theme-text);
    border: 1px solid var(--tapp_theme-border);
    border-radius: 4px;
    padding: 2px 6px;
    font-size: 12px;
}

/* ============================================
   OTP verification dialog
   ============================================ */

.tapp_otp_hint {
    font-size: 14px;
    color: var(--tapp_theme-text-muted);
    line-height: 1.5;
    margin: 0 0 20px;
}

.tapp_otp_field {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    margin: 0 0 16px;
}

.tapp_otp_field label {
    font-size: 12px;
    color: var(--tapp_theme-text-muted);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.tapp_otp_field input[type="text"] {
    font-size: 2em;
    text-align: center;
    letter-spacing: 0.35em;
    text-indent: 0.35em;
    font-variant-numeric: tabular-nums;
    width: 200px;
    padding: 10px 8px;
    border: 1px solid var(--tapp_theme-border);
    border-radius: 6px;
    background: var(--tapp_theme-surface);
    color: var(--tapp_theme-text);
}

.tapp_otp_field input[type="text"]:focus {
    outline: none;
    border-color: var(--tapp_theme-input-focus);
    box-shadow: 0 0 0 3px var(--tapp_input-focus-shadow);
}

.tapp_otp_error {
    font-size: 13px;
    color: var(--tapp_status-error);
    background: var(--tapp_status-error-light);
    border-radius: 4px;
    padding: 6px 10px;
    margin: 4px 0 0;
    width: 100%;
    text-align: center;
}

/* ============================================
   Avatar + profile panel
   ============================================ */

.tapp_avatar_btn {
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    line-height: 0;
    border-radius: 50%;
}
.tapp_avatar_btn:focus-visible {
    outline: 2px solid var(--tapp_theme-input-focus);
    outline-offset: 2px;
}

.tapp_avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: var(--tapp_brand-primary);
    color: var(--tapp_theme-text-inverted);
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0;
    user-select: none;
}

.tapp_avatar_lg {
    width: 44px;
    height: 44px;
    font-size: 18px;
    flex-shrink: 0;
}

.tapp_profile_wrap {
    position: relative;
}

/* Dropdown menu */
.tapp_profile_panel {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    min-width: 160px;
    background: var(--tapp_theme-surface);
    border: 1px solid var(--tapp_theme-border);
    border-radius: 8px;
    box-shadow: 0 8px 24px var(--tapp_theme-shadow);
    z-index: 500;
    overflow: hidden;
    padding: 4px 0;
}

.tapp_profile_menu {
    list-style: none;
    margin: 0;
    padding: 0;
}

.tapp_profile_menu_btn {
    display: flex;
    align-items: center;
    gap: 7px;
    width: 100%;
    padding: 8px 14px;
    background: none;
    border: none;
    font-size: 13px;
    color: var(--tapp_theme-text);
    text-align: left;
    cursor: pointer;
    white-space: nowrap;
}
.tapp_profile_menu_btn:hover {
    background: var(--tapp_theme-surface-alt);
}

.tapp_profile_menu_icon {
    font-size: 14px;
    line-height: 1;
    color: var(--tapp_theme-text-muted);
}

.tapp_profile_menu_sep {
    height: 1px;
    background: var(--tapp_theme-border-light);
    margin: 4px 0;
}

.tapp_profile_menu_danger {
    color: var(--tapp_status-error);
}
.tapp_profile_menu_danger:hover {
    background: var(--tapp_status-error-light);
}

/* Dialog content — used inside TApp.dialog.modal() tabs */
.tapp_avatar_sm {
    width: 22px;
    height: 22px;
    font-size: 11px;
}

.tapp_profile_table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}
.tapp_profile_table td {
    padding: 6px 8px;
    vertical-align: top;
}
.tapp_profile_table td:first-child {
    color: var(--tapp_theme-text-muted);
    white-space: nowrap;
    width: 1%;
    padding-right: 16px;
}

.tapp_profile_badge {
    display: inline-block;
    font-size: 10px;
    font-weight: 600;
    padding: 1px 6px;
    border-radius: 10px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    width: fit-content;
}
.tapp_profile_badge_corp {
    background: var(--tapp_status-info-light);
    color: var(--tapp_status-info);
}

.tapp_profile_module_tags {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    padding: 4px 0;
}
.tapp_profile_module_tag {
    font-size: 11px;
    font-family: monospace;
    padding: 2px 6px;
    border-radius: 4px;
    background: var(--tapp_theme-surface-alt);
    color: var(--tapp_theme-text);
    border: 1px solid var(--tapp_theme-border-light);
}

.tapp_profile_empty {
    font-size: 13px;
    color: var(--tapp_theme-text-muted);
    margin: 0;
}

/* ════════════════════════════════════════════════════════════════════════
   Side-tab layout — used by the Settings dialog (Identity / Access).
   ════════════════════════════════════════════════════════════════════════ */
.tapp_side_tabs {
    display:    flex;
    min-height: 220px;
    gap:        0;
}
.tapp_side_tab_nav {
    display:        flex;
    flex-direction: column;
    gap:            2px;
    padding:        8px 6px;
    border-right:   1px solid var(--tapp_theme-border-light);
    background:     var(--tapp_theme-surface-alt);
    min-width:      110px;
    flex-shrink:    0;
    border-radius:  0 0 0 4px;
}
.tapp_side_tab_btn {
    display:       block;
    width:         100%;
    padding:       7px 10px;
    text-align:    left;
    background:    transparent;
    border:        none;
    border-left:   3px solid transparent;
    border-radius: 0 4px 4px 0;
    cursor:        pointer;
    font:          inherit;
    font-size:     0.88em;
    color:         var(--tapp_theme-text-muted);
    transition:    background 120ms, color 120ms, border-color 120ms;
}
.tapp_side_tab_btn:hover:not([data-active]) {
    background: var(--tapp_theme-surface);
    color:      var(--tapp_theme-text);
}
.tapp_side_tab_btn[data-active] {
    border-left-color: var(--tapp_brand-primary);
    color:             var(--tapp_brand-primary);
    font-weight:       600;
    background:        var(--tapp_theme-surface);
}
.tapp_side_tab_panels {
    flex:       1;
    overflow-y: auto;
    padding:    8px 12px;
    max-height: 340px;
}

/* ════════════════════════════════════════════════════════════════════════
   Profile <details> cards — Identity tab in Settings dialog.
   ════════════════════════════════════════════════════════════════════════ */
.tapp_profile_card {
    border:        1px solid var(--tapp_theme-border-light);
    border-radius: 6px;
    margin-bottom: 8px;
    overflow:      hidden;
}
.tapp_profile_card_header {
    display:     flex;
    align-items: center;
    gap:         6px;
    padding:     8px 10px;
    cursor:      pointer;
    list-style:  none;
    background:  var(--tapp_theme-surface-alt);
    user-select: none;
    font-size:   13px;
}
.tapp_profile_card_header::-webkit-details-marker { display: none; }
.tapp_profile_card_header::marker               { content: ''; }
.tapp_profile_card:not([open]) > .tapp_profile_card_header::before {
    content:    '▶';
    font-size:  8px;
    color:      var(--tapp_theme-text-muted);
    flex-shrink: 0;
}
.tapp_profile_card[open] > .tapp_profile_card_header::before {
    content:    '▼';
    font-size:  8px;
    color:      var(--tapp_theme-text-muted);
    flex-shrink: 0;
}
.tapp_profile_card_email {
    flex:          1;
    font-family:   monospace;
    font-size:     12px;
    overflow:      hidden;
    text-overflow: ellipsis;
    white-space:   nowrap;
}
.tapp_profile_status_chip {
    font-size:   10px;
    padding:     2px 6px;
    border-radius: 10px;
    font-weight: 600;
    white-space: nowrap;
    flex-shrink: 0;
}
.tapp_profile_status_chip[data-status="ACTIVE"] {
    background: var(--tapp_status-success-light);
    color:      var(--tapp_status-success);
}
.tapp_profile_status_chip[data-status="SUSPENDED"] {
    background: var(--tapp_status-error-light);
    color:      var(--tapp_status-error);
}
.tapp_profile_status_chip[data-status="NEEDS_VERIFICATION"] {
    background: var(--tapp_status-warning-light);
    color:      #85620a;
}
.tapp_profile_card_inactive {
    opacity: 0.65;
}
.tapp_profile_card_body {
    padding:    8px 10px;
    border-top: 1px solid var(--tapp_theme-border-light);
    background: var(--tapp_theme-surface);
}
.tapp_profile_card_org {
    font-family: monospace;
    font-size:   11px;
    color:       var(--tapp_theme-text-muted);
    margin:      0 0 6px;
}
.tapp_profile_card_verified {
    font-family: inherit;
    font-size:   11px;
    color:       var(--tapp_status-success);
}
.tapp_profile_coverage_table {
    width:           100%;
    border-collapse: collapse;
    font-size:       12px;
}
.tapp_profile_coverage_table td {
    padding: 3px 0;
}
.tapp_profile_cov_module {
    font-family: monospace;
    font-size:   11px;
    width:       50%;
}
.tapp_profile_cov_dates {
    color:     var(--tapp_theme-text-muted);
    font-size: 11px;
    width:     42%;
}
.tapp_profile_cov_status {
    text-align:  center;
    font-weight: 700;
    color:       var(--tapp_status-success);
    width:       8%;
}

/* Mini Gantt in profile coverage cards */
.tapp_profile_gantt {
    margin-bottom: 10px;
    min-height:    20px;
}
.tapp_profile_gantt svg {
    display:   block;
    max-width: 100%;
}

/* ============================================
   Dark mode — Drop-only overrides for theme-private tokens.
   Standard --tapp_* tokens are darkened by the active layout/palette
   (currently classic-3eff supplies a dark block; if Drop needs
   different surface/text values when running standalone with no
   palette, set them here as --tapp_* overrides).
   ============================================ */

:root[tapp-theme="dark"] {
    /* Standard --tapp_* overrides (palettes don't yet ship dark variants;
       Drop supplies sensible defaults so dark mode flips background,
       text, and surfaces) */
    --tapp_theme-background:     #1a1f2e;
    --tapp_theme-surface:        #242a3a;
    --tapp_theme-surface-alt:    #2e3548;
    --tapp_theme-text:           #e0e4ea;
    --tapp_theme-text-muted:     #8a92a4;
    /* Text rendered on brand-colored surfaces (which don't flip with
       dark mode). Brand bgs are typically dark navy — light text on
       them contrasts in both modes. */
    --tapp_theme-text-inverted:  #ffffff;
    --tapp_theme-border:         #3a4258;
    --tapp_theme-border-light:   rgba(255, 255, 255, 0.08);
    --tapp_theme-shadow:         rgba(0, 0, 0, 0.6);

    /* Drop-private tints — darkened versions */
    --drop-bg-grid:    color-mix(in srgb, var(--tapp_brand-primary) 8%,  transparent);
    --drop-curve-tint: rgba(0, 0, 0, 0.55);

    /* Topbar overlays — dark frosted-glass */
    --drop-topbar-bg:     rgba(36,  42,  58,  0.72);
    --drop-topbar-border: rgba(255, 255, 255, 0.08);
    --drop-topbar-hover:  rgba(255, 255, 255, 0.06);
    --drop-topbar-press:  rgba(255, 255, 255, 0.12);
    --drop-topbar-pill:   rgba(255, 255, 255, 0.06);
    --drop-topbar-icon-stroke: %23e0e4ea;
}

/* The globe icon on the language <select> is a data:URL with a hard-
   coded stroke color; provide a dark-mode variant. */
:root[tapp-theme="dark"] #tapp_header .tapp_select {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23e0e4ea' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='10'/><path d='M2 12h20'/><path d='M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z'/></svg>");
}

/* Dropdown arrow on lang select <select> when expanded — hidden via styling. */

/* Search icon inside spotlight uses a hard-coded gray stroke; brighten in dark. */
:root[tapp-theme="dark"] .drop_spotlight_search::before {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a92a4' stroke-width='2.2' stroke-linecap='round'><circle cx='11' cy='11' r='7'/><path d='m21 21-4.3-4.3'/></svg>");
}

/* Tile hover uses hard-coded rgba; flip for dark. Scoped to submenu tiles only. */
:root[tapp-theme="dark"] #tapp_modules .tapp_submenu .tapp_menu_btn {
    background: rgba(95, 166, 227, 0.08);
}
:root[tapp-theme="dark"] #tapp_modules .tapp_submenu .tapp_menu_btn:hover,
:root[tapp-theme="dark"] #tapp_modules .tapp_submenu .tapp_menu_btn.active {
    background: rgba(95, 166, 227, 0.20);
    color: var(--tapp_theme-link-hover);
}

/* ============================================
   Backdrop
   ============================================ */

.drop_backdrop {
    position: fixed;
    inset: 0;
    background: var(--drop-curve-tint);
    backdrop-filter: blur(2px);
    opacity: 0;
    transition: opacity 280ms var(--drop-ease-soft);
    z-index: 40;
    pointer-events: none;
}
html[data-tapp-launcher="active"] .drop_backdrop {
    opacity: 1;
    pointer-events: auto;
}

/* ============================================
   Reduced motion
   ============================================ */

@media (prefers-reduced-motion: reduce) {
    .drop_curve,
    .drop_curve_3,
    .drop_spotlight,
    #tapp_landing_logo,
    .tapp_backdrop {
        transition-duration: 0.001ms !important;
    }
}

/* ════════════════════════════════════════════════════════════════════════
   Dialog buttons (chooser modal & generic dialog footer ul)
   The framework's TApp.dialog.modal output is:
       <h2>title</h2>
       <p>content</p>
       <nav><ul>
         <li><button data-dialog-btn="0">Local file…</button></li>
         …
       </ul></nav>
   Drop paints these as pill buttons with brand accent on the first.
   ════════════════════════════════════════════════════════════════════════ */
.tapp_dialog h2 {
    margin: 0 0 8px;
    font-size: 1.1em;
    color: var(--tapp_theme-text);
}
.tapp_dialog p {
    margin: 0 0 16px;
    color: var(--tapp_theme-text);
}
.tapp_dialog nav ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    flex-wrap: wrap;
}
.tapp_dialog nav ul button {
    padding: 6px 14px;
    background: var(--tapp_theme-surface-alt);
    color: var(--tapp_theme-text);
    border: 1px solid var(--tapp_theme-border);
    border-radius: 9999px;
    cursor: pointer;
    font: inherit;
    transition: background-color 120ms, border-color 120ms;
}
.tapp_dialog nav ul button:hover {
    background: var(--drop-topbar-hover);
    border-color: var(--tapp_brand-secondary);
}
/* First button in the list is the primary action — filled accent. */
.tapp_dialog nav ul li:first-child button {
    background: var(--tapp_brand-secondary);
    color: var(--tapp_theme-text-inverted);
    border-color: var(--tapp_brand-secondary);
}
.tapp_dialog nav ul li:first-child button:hover {
    background: var(--tapp_theme-link-hover);
    border-color: var(--tapp_theme-link-hover);
}

/* ════════════════════════════════════════════════════════════════════════
   Library dialog — Drop paint over the markup the framework emits.
   Frosted-card surface (matches the body card aesthetic), 4 px canvas
   trench border (matches the toolbar/section-arrows pills), rounded
   corners, scrollable list.
   ════════════════════════════════════════════════════════════════════════ */
.tapp_library_dialog {
    width: min(640px, 90vw);
    max-width: none;
    height: 560px;
    max-height: 90vh;
    padding: 0;
    background: var(--drop-topbar-bg);
    backdrop-filter: saturate(160%) blur(20px);
    -webkit-backdrop-filter: saturate(160%) blur(20px);
    color: var(--tapp_theme-text);
    border: 4px solid var(--tapp_theme-background);
    border-radius: 18px;
    box-shadow: 0 12px 40px var(--tapp_theme-shadow);
}
.tapp_library_dialog[open] {
    display: flex;
    flex-direction: column;
}
.tapp_library_dialog::backdrop {
    background: rgba(0, 0, 0, 0.4);
    backdrop-filter: blur(2px);
}

/* Header — brand-coloured strip with title + close. */
.tapp_library_header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 18px;
    background: var(--tapp_brand-primary);
    color: var(--tapp_theme-text-inverted);
    border-radius: 14px 14px 0 0;
}
.tapp_library_header h2 {
    margin: 0;
    color: inherit;
    font-size: 1.0em;
    font-weight: 600;
    letter-spacing: 0.2px;
}
.tapp_library_close {
    background: transparent;
    border: 0;
    cursor: pointer;
    color: inherit;
    font-size: 1.4em;
    line-height: 1;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background-color 120ms;
}
.tapp_library_close:hover {
    background: rgba(255, 255, 255, 0.18);
}

/* Search — pill input matching the toolbar input style. */
.tapp_library_search {
    padding: 12px 18px;
}
.tapp_library_search input {
    width: 100%;
    height: 30px;
    padding: 0 14px;
    background: var(--tapp_theme-surface-alt);
    color: var(--tapp_theme-text);
    border: 1px solid var(--tapp_theme-border);
    border-radius: 9999px;
    font: inherit;
    outline: none;
    transition: border-color 120ms, box-shadow 120ms;
}
.tapp_library_search input::placeholder {
    color: var(--tapp_theme-text-muted);
}
.tapp_library_search input:focus {
    border-color: var(--tapp_brand-secondary);
    box-shadow: 0 0 0 2px var(--drop-curve-tint);
}

/* Table — flat, minimal lines; selected row in accent.
   Fixed-height body region (matches the page size of 5 rows) so the
   dialog doesn't grow/shrink as results change. */
.tapp_library_table {
    flex: 1 1 auto;
    margin: 0 18px 12px;
    border-collapse: collapse;
    width: calc(100% - 36px);
    font-size: 0.9em;
}
.tapp_library_table thead th {
    text-align: left;
    padding: 6px 10px;
    border-bottom: 2px solid var(--tapp_theme-border);
    color: var(--tapp_theme-text-muted);
    font-size: 0.85em;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.4px;
}
.tapp_library_table tbody {
    display: block;
    height: 290px;
    overflow-y: auto;
}
.tapp_library_table thead, .tapp_library_table tbody tr {
    display: table;
    width: 100%;
    table-layout: fixed;
}
.tapp_library_table tbody td {
    padding: 8px 10px;
    border-bottom: 1px solid var(--tapp_theme-border);
    color: var(--tapp_theme-text);
    vertical-align: top;
}
.tapp_library_table tbody td:first-child {
    width: 36px;
    text-align: center;
}
.tapp_library_table tbody label {
    cursor: pointer;
    font-weight: 600;
}
.tapp_library_table tbody tr:has(input:checked) {
    background: var(--drop-curve-tint);
}
.tapp_library_table tbody tr:has(input:checked) td:first-child {
    box-shadow: inset 4px 0 0 0 var(--tapp_brand-secondary);
}

/* Capability chips — small brand-tint pills, one per capability. */
.tapp_library_cap {
    display: inline-block;
    padding: 1px 8px;
    margin: 0 2px 2px 0;
    background: var(--drop-curve-tint);
    color: var(--tapp_brand-secondary);
    border: 1px solid var(--tapp_brand-secondary);
    border-radius: 9999px;
    font-size: 0.78em;
    font-weight: 600;
    line-height: 1.4;
    letter-spacing: 0.2px;
}

.tapp_library_empty {
    padding: 24px 18px;
    text-align: center;
    color: var(--tapp_theme-text-muted);
}

/* Pager — prev/next pill buttons + centered page info. */
.tapp_library_pager {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 8px 18px 12px;
}
.tapp_library_pager_btn {
    padding: 4px 14px;
    background: var(--tapp_theme-surface-alt);
    color: var(--tapp_theme-text);
    border: 1px solid var(--tapp_theme-border);
    border-radius: 9999px;
    cursor: pointer;
    font: inherit;
    font-size: 0.85em;
    transition: background-color 120ms, border-color 120ms;
}
.tapp_library_pager_btn:hover:not([disabled]) {
    background: var(--drop-topbar-hover);
    border-color: var(--tapp_brand-secondary);
}
.tapp_library_pager_btn[disabled] {
    color: var(--tapp_theme-text-muted);
    cursor: not-allowed;
    opacity: 0.5;
}
.tapp_library_pager_info {
    color: var(--tapp_theme-text-muted);
    font-size: 0.85em;
    font-variant-numeric: tabular-nums;
    min-width: 60px;
    text-align: center;
}

/* Footer — Cancel (subtle) + Load (primary accent), pill style. */
.tapp_library_footer {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    padding: 12px 18px;
    border-top: 1px solid var(--tapp_theme-border);
}
.tapp_library_footer button {
    padding: 6px 16px;
    background: var(--tapp_theme-surface-alt);
    color: var(--tapp_theme-text);
    border: 1px solid var(--tapp_theme-border);
    border-radius: 9999px;
    cursor: pointer;
    font: inherit;
    transition: background-color 120ms, border-color 120ms;
}
.tapp_library_footer button:hover {
    background: var(--drop-topbar-hover);
    border-color: var(--tapp_brand-secondary);
}
.tapp_library_footer .tapp_btn-primary {
    background: var(--tapp_brand-secondary);
    color: var(--tapp_theme-text-inverted);
    border-color: var(--tapp_brand-secondary);
}
.tapp_library_footer .tapp_btn-primary:hover {
    background: var(--tapp_theme-link-hover);
    border-color: var(--tapp_theme-link-hover);
}
.tapp_library_footer .tapp_btn-primary[disabled] {
    background: var(--tapp_theme-surface-alt);
    color: var(--tapp_theme-text-muted);
    border-color: var(--tapp_theme-border);
    cursor: not-allowed;
    opacity: 0.6;
}

/* ════════════════════════════════════════════════════════════════════════
   Charts — Drop-specific paints
   The framework emits chart SVG with stable classes (.tapp_flowchart_*).
   Tree mode is left mostly to the framework defaults; sunburst gets the
   richer, sequences-style treatment: filled arcs colored by top-level
   branch (data-branch="N"), thin ring separators, hover lifts the
   focused arc-and-ancestors above the rest.
   ════════════════════════════════════════════════════════════════════════ */

/* Chart canvas border — frames the rendered chart so it reads as a
   bounded panel within the workspace. Targets the chart host element
   directly via the framework's data-tapp-chart-kind attribute, so
   any chart kind (flowchart / funnel / future) inherits the frame. */
[data-tapp-chart-kind] {
    border: 1px solid var(--tapp_theme-border);
    border-radius: 10px;
    background: var(--tapp_theme-surface);
    padding: 8px;
    box-shadow: 0 1px 2px var(--tapp_theme-shadow);
}

/* Workspace acts as the positioning context for the floating legend
   pill below — it docks to the chart's upper-right edge. */
#tcli_epi_workspace {
    position: relative;
}

/* Chart and table sections inside the workspace are mutually-
   exclusive views (toolbar toggle flips `hidden`). When visible,
   each fills a viewport-bounded area and scrolls internally so the
   page doesn't stretch tall. */
#tcli_epi_chart_section,
#tcli_epi_table_section {
    height:        clamp(360px, 60vh, 720px);
    min-height:    0;
    overflow:      auto;
    padding:       8px;
    background:    var(--tapp_theme-surface);
    display:       flex;
    flex-direction: column;
}
/* Explicit [hidden] override: id-selector specificity beats the
   browser's default `[hidden] { display: none }`, so the rule above
   would keep both sections visible after the toolbar toggle flips
   `hidden`. Re-assert display:none for the inactive section. */
#tcli_epi_chart_section[hidden],
#tcli_epi_table_section[hidden] {
    display: none;
}

/* Fullscreen — model.requestFullscreen() makes the feature
   <section> fill the viewport. Inside, the model section flexes
   column so the toolbar sits at top and the workspace fills the
   rest. Workspace flexes column, the "Model details" inner section
   flexes to fill, the chart/table section flexes inside that to
   fill. Legends + references are hidden in fullscreen — the user
   asked for the active VIEW to take over, not the whole card. */
section.tapp_section[data-section="model"]:fullscreen {
    background:     var(--tapp_theme-surface);
    display:        flex;
    flex-direction: column;
    height:         100%;
    width:          100%;
    padding:        0;
    margin:         0;
}
section.tapp_section[data-section="model"]:fullscreen #tcli_epi_workspace {
    flex:           1 1 auto;
    min-height:     0;
    display:        flex;
    flex-direction: column;
}
section.tapp_section[data-section="model"]:fullscreen #tcli_epi_model_details {
    /* the "Model details" wrapper section flexes to fill the
       workspace; its child chart/table section flexes inside.
       Targets the wrapper by id (not `> section`) so the legends
       and references sections — also direct-child <section>s of
       the workspace — don't pick up flex-grow and stay hidden via
       the display:none rule below. */
    flex:           1 1 auto;
    min-height:     0;
    display:        flex;
    flex-direction: column;
}
section.tapp_section[data-section="model"]:fullscreen #tcli_epi_chart_section,
section.tapp_section[data-section="model"]:fullscreen #tcli_epi_table_section {
    flex:       1 1 auto;
    min-height: 0;
    height:     auto;       /* unbind the clamp; flex sizing takes over */
}
/* Hide the legends + references blocks in fullscreen — fullscreen
   means "give the active view all the space"; secondary chrome
   stays out. Exits cleanly: when :fullscreen drops these stop
   matching and the blocks come back. */
section.tapp_section[data-section="model"]:fullscreen #tcli_epi_legends,
section.tapp_section[data-section="model"]:fullscreen .tapp_references {
    display: none;
}

/* tapp_popover — framework primitive (see DEVELOPER_GUIDE.md →
   "Framework UI primitives"). Singleton floating box appended to
   <body> by TApp.popover.show(), absolute-positioned at an anchor.
   Drop paints background + border + shadow; framework owns
   positioning + outside-click dismissal. */
.tapp_popover {
    position:      absolute;
    z-index:       10000;
    max-width:     min(420px, 90vw);
    max-height:    60vh;
    overflow-y:    auto;
    padding:       0.75em 1em;
    background:    var(--tapp_theme-surface);
    color:         var(--tapp_theme-text);
    border:        1px solid var(--tapp_theme-border);
    border-radius: 4px;
    box-shadow:    0 4px 12px rgba(0, 0, 0, 0.2);
    font-size:     0.9em;
    line-height:   1.4;
}
.tapp_popover > ol {
    margin:     0;
    padding:    0 0 0 1.5em;
    list-style: decimal;
}
.tapp_popover > ol li + li { margin-top: 0.5em; }
.tapp_popover[hidden] { display: none; }
/* Chart elements that carry data-cite-refs (CSV) get a cursor cue. */
#tcli_epi_flowchart [data-cite-refs] { cursor: pointer; }
sup[data-cite-ref] {
    cursor:         pointer;
    font-size:      0.75em;
    vertical-align: super;
    line-height:    1;
    margin-left:    0.15em;
    user-select:    none;
}
#tcli_epi_chart_section > #tcli_epi_flowchart,
#tcli_epi_table_section > #tcli_epi_table_host {
    flex:          1 1 auto;
    min-height:    0;
    overflow:      auto;
}


/* Table — folder-like, with leaves bold and a total row at the bottom.
   thead + tfoot are sticky-pinned so the user can scroll a long body
   between them without losing column context or the running total. */
/* Header — high-contrast inverse band so columns read at a glance. In
   light mode the body text (--tapp_theme-text) is dark, so we use it as
   the bg with --tapp_theme-text-inverted on top → dark band, white text.
   In dark mode the same tokens flip naturally: --tapp_theme-text is
   light, --tapp_theme-text-inverted is dark → light band, dark text. The
   header always lands on the OPPOSITE end of the body's contrast scale,
   regardless of which mode is active. */
.tapp_table thead th {
    background: var(--tapp_theme-text);
    color: var(--tapp_theme-text-inverted);
    text-align: left;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    padding: 6px 10px;
    border-bottom: 1px solid var(--tapp_theme-border);
    position: sticky;
    top: 0;
    z-index: 2;
}
.tapp_table tfoot td {
    position: sticky;
    bottom: 0;
    z-index: 2;
    background: var(--tapp_theme-surface);
}

/* Population row (level 0) pinned just under the header. The pixel
   top offset matches Drop's thead height (font 11px + padding 6+6
   + 1px border ≈ 30px).
   Caveats with sticky <td> + border-collapse: collapse:
     - Cell backgrounds don't paint over collapsed borders; the row
       beneath bleeds through. Use background-clip: padding-box and
       a higher z-index than thead/tfoot cells.
     - border-bottom on a sticky cell drops the bottom edge as the
       cell sticks; use box-shadow inset to draw the divider line. */
.tapp_table tbody tr[data-level="0"] > td {
    position: sticky;
    top: 30px;
    z-index: 3;
    background-color: var(--tapp_theme-surface);
    background-clip: padding-box;
    border-bottom: none;
    box-shadow: inset 0 -1px 0 var(--tapp_theme-border);
}
/* Data rows — plain surface bg; non-leaf rows use regular weight,
   leaves get a brand-tinted band (see leaf rule below). */
.tapp_table tbody td {
    font-size: 13px;
    padding: 4px 10px;
    border-bottom: 1px solid var(--tapp_theme-border-light);
    color: var(--tapp_theme-text);
    background: var(--tapp_theme-surface);
}
.tapp_table [data-numeric] {
    text-align: right;
    font-variant-numeric: tabular-nums;
    /* Monospace face so figures read as data and align column-to-column
       (reinforces tabular-nums). System mono stack — no web font. */
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
                 "Liberation Mono", monospace;
}
/* Centered numeric variant — keeps tabular/mono figures but centers the
   stack (e.g. a rate over its CI line). */
.tapp_table [data-numeric="center"] { text-align: center; }
.tapp_table[data-multiyear] thead th:first-child {
    /* Cohort header stays left-aligned in multi-year — overrides the
       blanket [data-numeric] on header cells. */
    text-align: left;
}
/* Framework primitive — collapsible subsection
   `TApp.createSubsection({ collapsible: true })` emits
   <details><summary>…</summary>…</details>. Drop paints the
   summary as a section heading band (similar to non-collapsible
   <section><h3>), with the native disclosure triangle preserved.
   The contained content sits below in a card-like surface. */
details > summary {
    cursor:        pointer;
    padding:       8px 12px;
    background:    color-mix(in oklab, var(--tapp_brand-primary) 10%, transparent);
    color:         var(--tapp_theme-text);
    font-weight:   700;
    font-size:     0.95em;
    border-radius: 4px;
    margin-top:    12px;
    user-select:   none;
}
details > summary mark {
    background:  var(--tapp_brand-primary);
    color:       var(--tapp_theme-text-inverted);
    padding:     0 6px;
    border-radius: 3px;
}
details[open] > summary {
    margin-bottom: 4px;
}

/* Framework primitive — card. Any element carrying [data-card]
   gets a contained surface with border + shadow + bg, suitable
   for wrapping a focal table / chart / form. Centered horizontally
   with auto margins; max-width caps very wide content while
   keeping smaller content snug. */
[data-card] {
    background:    var(--tapp_theme-surface);
    border:        1px solid var(--tapp_theme-border);
    border-radius: 6px;
    box-shadow:    0 1px 3px var(--tapp_theme-shadow, rgba(0, 0, 0, 0.08));
    padding:       12px;
    margin:        8px auto;
    max-width:     100%;
}

/* Framework primitive — a nested-section heading band that also hosts
   a trailing action (a close ×). When the band contains a
   .tapp_panel_close it becomes a flex row, so the title sits left and
   the × sits at the band's right edge — INSIDE the band background,
   not floating beside it. The selector mirrors the nested-section band
   rule's context + one extra (:has) so it out-specifies that rule's
   display:block. */
#tapp_workspace > section.tapp_feature_section
    .tapp_section .tapp_section .tapp_section_heading:has(> .tapp_panel_close) {
    display:         flex;
    align-items:     center;
    justify-content: space-between;
    gap:             8px;
}
/* Framework primitive — close (×) control for panels/popovers.
   Transparent by default so it reads cleanly on a tinted heading band;
   a tint appears on hover. */
.tapp_panel_close {
    flex:          0 0 auto;
    width:         22px;
    height:        22px;
    padding:       0;
    border:        0;
    border-radius: 6px;
    background:    transparent;
    color:         var(--tapp_theme-text);
    font-size:     15px;
    line-height:   1;
    cursor:        pointer;
}
.tapp_panel_close:hover {
    background: color-mix(in oklab, var(--tapp_brand-primary) 22%, transparent);
}

/* Framework primitive — definition list as a compact term/value grid
   (label column sized to content, value column fills). Reusable for
   any key/value readout. */
.tapp_deflist {
    display:               grid;
    grid-template-columns: max-content 1fr;
    gap:                   4px 16px;
    margin:                4px 0 0;
}
.tapp_deflist dt {
    font-weight: 600;
    font-size:   12px;
    color:       color-mix(in oklab, var(--tapp_theme-text) 70%, transparent);
}
.tapp_deflist dd {
    margin:    0;
    font-size: 13px;
    color:     var(--tapp_theme-text);
}

/* Framework primitive — muted explanatory footnote. */
.tapp_note {
    margin:     8px 0 0;
    font-size:  11px;
    font-style: italic;
    color:      color-mix(in oklab, var(--tapp_theme-text) 65%, transparent);
}

/* Framework primitive — stat. A prominent, centered numeric figure
   (e.g. a response rate). Resets small-caps/tracking it may inherit
   from a styled container so the number reads plainly. Rides the
   triad's accent-b "quantitative readout" hue (primary fallback). */
.tapp_stat {
    display:           block;
    margin-top:        4px;
    text-align:        center;
    font-variant-caps: normal;
    letter-spacing:    0;
    font-weight:       700;
    font-size:         20px;
    line-height:       1.1;
    color:             var(--tapp_brand-accent-b, var(--tapp_brand-primary));
}

/* Framework primitive — link button. A <button> that reads as an
   inline text link (no chrome), centered as a full-width block so it
   sits under stacked content. */
.tapp_linkbtn {
    display:               block;
    width:                 100%;
    margin-top:            8px;
    padding:               0;
    border:                0;
    background:            none;
    cursor:                pointer;
    font:                  inherit;
    font-variant-caps:     normal;
    letter-spacing:        0;
    font-weight:           500;
    font-size:             11px;
    text-align:            center;
    color:                 var(--tapp_brand-primary);
    text-decoration:       underline;
    text-underline-offset: 2px;
}
.tapp_linkbtn:hover {
    text-decoration-thickness: 2px;
}
/* Drop paints the framework data-icon="search" hint as a trailing
   magnifying-glass (🔍) after the link label. inline-block stops the
   link underline from running under the glyph. */
.tapp_linkbtn[data-icon="search"]::after {
    content:      "🔍";
    display:      inline-block;
    margin-left:  4px;
}
/* Per-group edit affordance (✎) lives in its own narrow column, immediately
   right of the indication / intervention name. */
/* Inline search row above a .tapp_table (e.g. packages panel). */
.tapp_table_search_wrap {
    display:       flex;
    align-items:   center;
    gap:           6px;
    margin-bottom: 6px;
}
.tapp_table_search_icon { font-size: 13px; flex-shrink: 0; }
.tapp_table_search {
    flex:         1;
    min-width:    0;
    padding:      4px 8px;
    border:       1px solid color-mix(in oklab, var(--tapp_theme-text) 20%, transparent);
    border-radius: 4px;
    background:   color-mix(in oklab, var(--tapp_theme-text) 5%, transparent);
    color:        var(--tapp_theme-text);
    font-size:    12px;
    line-height:  1.4;
}
.tapp_table_search:focus { outline: 2px solid var(--tapp_brand-primary); outline-offset: -1px; }
.tapp_table[data-compare] th[data-col="edit"],
.tapp_table[data-compare] td[data-col="edit"] {
    width:       1%;
    text-align:  center;
    white-space: nowrap;
}
.tapp_editinline {
    padding:     0 0.15em;
    font-size:   0.95em;
    line-height: 1;
    opacity:     0.65;
}
.tapp_editinline:hover,
.tapp_editinline:focus-visible { opacity: 1; }
/* Override cue: authored value struck through + dimmed, new value beside it. */
.tapp_override_orig {
    text-decoration: line-through;
    opacity:         0.5;
    margin-right:    0.35em;
}
.tapp_override_new { font-weight: 600; }
/* Edit-dialog number inputs: compact, right-aligned tabular figures. */
#tapp_dialog_modal .tapp_table input[type="number"] {
    width:                9em;
    text-align:           right;
    font-variant-numeric: tabular-nums;
    /* No spinner chevrons — typing only (share + price edits). */
    -moz-appearance:      textfield;
    appearance:           textfield;
}
#tapp_dialog_modal .tapp_table input[type="number"]::-webkit-inner-spin-button,
#tapp_dialog_modal .tapp_table input[type="number"]::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin:             0;
}
/* Edit-dialog cells don't wrap — the dialog sizes to content, so long pack
   names and the value+unit (e.g. "71 482.01  ARS") stay on one line.
   Scoped to edit tables; compare/ledger ([data-compare]) and form
   ([data-form]) dialogs keep normal wrapping. */
#tapp_dialog_modal .tapp_table:not([data-compare]):not([data-form]) th,
#tapp_dialog_modal .tapp_table:not([data-compare]):not([data-form]) td {
    white-space: nowrap;
}
/* Form-style dialog tables ([data-form]): labels in <thead>, all inputs
   in one <tbody> row. Standard tapp_table thead dark band applies.
   Inputs/selects fill their cell width. */
#tapp_dialog_modal .tapp_table[data-form] {
    width: 100%;
}
#tapp_dialog_modal .tapp_table[data-form] td {
    vertical-align: top;
    padding-top:    6px;
}
#tapp_dialog_modal .tapp_table[data-form] td input,
#tapp_dialog_modal .tapp_table[data-form] td select {
    width:      100%;
    box-sizing: border-box;
    min-width:  6rem;
}

/* Transposed-table thead: don't paint the dark inverted band —
   the drug-column headers carry inline product logos which need a
   neutral background. Override the generic .tapp_table thead th rule
   above with explicit surface bg + body text color. */
.tapp_table[data-transposed] thead th {
    background:     var(--tapp_theme-surface);
    color:          var(--tapp_theme-text);
    text-transform: none;
    letter-spacing: 0;
    font-size:      inherit;
}

/* Transposed-table sizing: fixed layout + 100% width so every drug
   column gets the same width regardless of how much content sits
   inside it. A drug with 5 phases and a drug with 3 phases now
   render side-by-side at the same column width — Adalimumab is no
   longer dwarfed next to Infliximab.

   --n-drugs is set inline by tmec.js; min-width = (n × 220px) gives
   each drug column a readable floor (logos, phase tile labels stay
   un-truncated). Once min-width exceeds the panes container's
   width, the container's overflow-x: auto kicks in and the table
   scrolls horizontally — fits N=2..5 drugs in the capped card with
   no scroll, scrolls from N=6 up. */
.tapp_table[data-transposed] {
    width:        100%;
    min-width:    calc(var(--n-drugs, 2) * 220px);
    margin:       0 auto;
    table-layout: fixed;
}

/* CPR Model workspace: when the per-endpoint tables exceed the
   feature card's width (combos with long drug names, many protocols),
   scroll horizontally inside the workspace rather than pushing past
   the card border. The card itself stays a fixed-width focal
   surface; only the tables underneath move under the scrollbar. */
.tapp_metricboard {
    overflow-x: auto;
}
/* Per-endpoint tables in this workspace are small (a few rows each);
   the framework's sticky <thead> + z-index: 2 is overkill AND it
   creates a new stacking context inside the workspace card that
   wins z-index battles against the toolbar's multiselect popover
   (z-index: 99000 in the toolbar's own stacking context — cross-
   context z-index doesn't compare directly, so the sticky header
   paints over the open dropdown). Pinning the thead static here
   removes the stacking context entirely so the popover renders
   above the table contents as intended. */
.tapp_matrix thead th {
    position: static;
}

/* ───── tmec-cpr Drop final-design draft ─────────────────────────
   Hides the table header (the body now self-explains via metric
   labels in column 4 + the Result column structure), turns each
   endpoint table into its own card, emphasizes the NNT/NTR row
   as the headline visual, and routes $ rows onto the triad's
   accent-a complementary hue so silhouettes (primary) and bars
   (accent) read as distinct visual languages. */

/* 1. Hide thead — the metric-label column ("$/Patient" / "$/Responder"
   / "NNT") + the per-cell axis labels make the columns self-
   explanatory; the header row is dead pixels at this point. */
.tapp_matrix thead {
    display: none;
}

/* 2. Card per endpoint table. The outer [data-card] loses its
   paint (it just stacks the per-table cards now); each .tapp_table
   inside gets the surface bg + border + radius + shadow + spacing
   so each endpoint reads as a discrete analysis block. */
.tapp_metricboard > section.tapp_section > [data-card] {
    background:    transparent;
    border:        0;
    box-shadow:    none;
    padding:       0;
    margin:        8px auto;
    display:       flex;
    flex-direction: column;
    gap:           14px;
}
.tapp_matrix {
    background:    var(--tapp_theme-surface);
    border:        1px solid var(--tapp_theme-border);
    border-radius: 8px;
    box-shadow:    0 1px 3px var(--tapp_theme-shadow, rgba(0, 0, 0, 0.08));
    padding:       12px 14px;
    border-collapse: separate;
    border-spacing: 0;
}

/* 3. Intervention names — bold + small-caps for a typographic
   "stately label" treatment. Slightly larger + tracking so they
   read as the dominant text on the row. */
.tapp_matrix tbody td[data-col="drug"] {
    font-weight:    700;
    font-size:      14px;
    font-variant-caps: all-small-caps;
    letter-spacing: 0.04em;
    color:          var(--tapp_theme-text);
}

/* 4. NNT/NTR row — the headline. Bigger metric-label + colorful
   num cell on the primary brand. */
.tapp_matrix tbody tr[data-metric="metric"] > td[data-col="metric-label"] {
    font-weight: 700;
    font-size:   15px;
    color:       var(--tapp_brand-primary);
}
.tapp_matrix tbody tr[data-metric="metric"] > td[data-col="value"] > [data-col="num"] {
    font-size:   22px;
    font-weight: 800;
    color:       var(--tapp_brand-primary);
    line-height: 1;
}

/* 5. $ rows — visually subordinate. Smaller, lighter label;
   num cell + bar + axis in the triad's accent-b (the green-
   leaning complementary hue at h+120° from primary). Green is
   the conventional money association in most locales and reads
   less aggressively than the warm accent-a (red/coral) we
   trialed first. The eye reads "money lane = green-accent" /
   "patient lane = primary" as a single chord across the row.

   PALETTE FALLBACK: only the 3eff palette currently defines
   --tapp_brand-accent-a + -b (other palettes ship just primary).
   We use `var(--tapp_brand-accent-b, var(--tapp_brand-primary))`
   so non-3eff palettes still paint a visible bar (matching the
   silhouettes' primary instead of vanishing). Future palettes
   that want the warm/cool split for free should ship the accent
   tokens; in the meantime the result-row hierarchy is preserved
   via size/weight, not hue. */
.tapp_matrix tbody tr[data-metric="cost-per-patient"] > td[data-col="metric-label"],
.tapp_matrix tbody tr[data-metric="cost-per-responder"] > td[data-col="metric-label"] {
    font-size: 12px;
    color:     color-mix(in oklab, var(--tapp_theme-text) 75%, transparent);
}
.tapp_matrix tbody tr[data-metric="cost-per-patient"] > td[data-col="value"] > [data-col="num"],
.tapp_matrix tbody tr[data-metric="cost-per-responder"] > td[data-col="value"] > [data-col="num"] {
    color: var(--tapp_brand-accent-b, var(--tapp_brand-primary));
}

/* 6. $ bars + money axis on accent-a (with primary fallback). */
.tapp_matrix tr[data-metric="cost-per-patient"] [data-graph="bar"] > meter::-webkit-meter-optimum-value,
.tapp_matrix tr[data-metric="cost-per-patient"] [data-graph="bar"] > meter::-webkit-meter-suboptimum-value,
.tapp_matrix tr[data-metric="cost-per-patient"] [data-graph="bar"] > meter::-webkit-meter-even-less-good-value,
.tapp_matrix tr[data-metric="cost-per-responder"] [data-graph="bar"] > meter::-webkit-meter-optimum-value,
.tapp_matrix tr[data-metric="cost-per-responder"] [data-graph="bar"] > meter::-webkit-meter-suboptimum-value,
.tapp_matrix tr[data-metric="cost-per-responder"] [data-graph="bar"] > meter::-webkit-meter-even-less-good-value {
    background: var(--tapp_brand-accent-b, var(--tapp_brand-primary));
}
.tapp_matrix tr[data-metric="cost-per-patient"] [data-graph="bar"] > meter::-moz-meter-bar,
.tapp_matrix tr[data-metric="cost-per-responder"] [data-graph="bar"] > meter::-moz-meter-bar {
    background: var(--tapp_brand-accent-b, var(--tapp_brand-primary));
}
.tapp_matrix tr[data-metric="cost-per-patient"] [data-axis="money"],
.tapp_matrix tr[data-metric="cost-per-responder"] [data-axis="money"] {
    color: color-mix(in oklab, var(--tapp_brand-accent-b, var(--tapp_brand-primary)) 70%, transparent);
}

/* 7. No-wrap + alignment + bold on the metadata columns.
   Endpoint and Protocol cells must stay on a single line (the
   wrap mid-token "ACCENT-" / "I" reads as a typo). Endpoint
   gets the same bold typographic treatment as Intervention so
   the trio (endpoint / drug / protocol) reads as a clean
   identity strip on the left side of each card.

   Alignment between tables: a fixed min-width on the endpoint
   column makes the strip the same horizontal slot in every
   card, so the eye lines up the analyses block-to-block even
   when each card has a different intervention/protocol payload. */
/* Protocol + drug stay single-line (a wrap mid-token like "ACCENT-"
   / "I" reads as a typo). The endpoint now shows a localized name
   ("≥5% body-weight loss at 72 weeks") so it WRAPS within its fixed
   column instead of blowing the strip wide. */
.tapp_matrix tbody td[data-col="protocol"],
.tapp_matrix tbody td[data-col="drug"] {
    white-space: nowrap;
}
.tapp_matrix tbody td[data-col="endpoint"] {
    font-weight:    700;
    font-size:      14px;
    font-variant-caps: all-small-caps;
    letter-spacing: 0.04em;
    color:          var(--tapp_brand-primary);
    /* FIXED width (not min-width) so the column lines up across
       cards — min-width lets short endpoints snap to the floor
       while long ones expand, breaking the per-card alignment.
       Width here is sized for the longest endpoint we expect
       ("REMISSION-CDAI-150" at 14px bold small-caps ≈ 160px;
       180px gives breathing room + padding). */
    width:          180px;
    min-width:      180px;
    max-width:      180px;
    vertical-align: middle;
    text-align:     center;
    /* Light tinted background that follows the card's left
       edge — the cell rowspans the whole table so the radius
       sits at the card's left top/bottom corners. */
    background: color-mix(in oklab, var(--tapp_brand-primary) 8%, transparent);
    border-top-left-radius:    7px;
    border-bottom-left-radius: 7px;
    padding-left:  14px;
    padding-right: 14px;
}

/* End tmec-cpr Drop final-design draft */

/* Result umbrella spans Graph + Value cells (thead uses
   colspan=2). The Graph cell takes ALL leftover horizontal width;
   the Value cell sizes to its content (the formatted number).
   `width: 100%` on a single column with auto siblings + a fixed
   value column = browsers grow the graph column to fill. */
.tapp_matrix th[data-col="result"],
.tapp_matrix tbody td[data-col="graph"] {
    width: 100%;
}

/* Graph cell — hosts a vertical stack: graph on top, axis tick
   labels below. min-width keeps the slot wide enough to read at
   any window size; the cell itself paints flush with the row. */
.tapp_matrix tbody td[data-col="graph"] {
    padding-right: 14px;
    min-width: 220px;
}
.tapp_matrix [data-graph-wrap] {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
}
.tapp_matrix [data-graph-wrap] > [data-graph] {
    display: inline-flex;
    align-items: center;
    /* Slot height owned per graph type below (silhouettes dominate,
       bars recede). */
}
/* Value cell — number only, right-aligned. */
.tapp_matrix tbody td[data-col="value"] {
    text-align: right;
    padding-right: 14px;
    white-space: nowrap;
}
.tapp_matrix tbody td[data-col="value"] > [data-col="num"] {
    font-variant-numeric: tabular-nums;
    color: var(--tapp_theme-text);
}

/* Axis row — tick labels positioned absolutely so they align under
   their corresponding silhouette (N-axis) or bar percentage
   ($-axis) without measuring the DOM. The container is
   position:relative + a fixed height to leave room for one line
   of tiny labels. Empty until a Run produces values. */
.tapp_matrix [data-graph-wrap] > [data-axis] {
    position: relative;
    display: block;
    height: 12px;
    font-size: 10px;
    color: color-mix(in oklab, var(--tapp_theme-text) 55%, transparent);
    font-variant-numeric: tabular-nums;
}
.tapp_matrix [data-graph-wrap] > [data-axis] > span {
    line-height: 12px;
    white-space: nowrap;
}

/* Combo boundary — bolder break between (drug × protocol) blocks.
   Stamped on the FIRST metric row of every combo except the first
   in a table. The thicker top border + extra top padding make each
   (drug × protocol) trio read as a distinct unit. The cells the
   row carries (drug + protocol with rowspan=3) inherit the rule
   via the > td selector, so the border crosses every column. */
.tapp_matrix tbody tr[data-combo-boundary="yes"] > td {
    border-top: 2px solid color-mix(in oklab, var(--tapp_theme-text) 22%, transparent);
    padding-top: 10px;
}

/* Legend — sits below the result card. Two stacked lines: the
   silhouette legend (mode-aware) + the bar legend (mode-agnostic).
   Compact, muted, italic — explanatory text, not part of the
   primary data flow. */
.tapp_metricboard [data-legend] {
    margin: 8px 0 0;
    padding: 0 4px;
    font-size: 11px;
    line-height: 1.5;
    font-style: italic;
    color: color-mix(in oklab, var(--tapp_theme-text) 70%, transparent);
}
.tapp_metricboard [data-legend] > span {
    display: block;
}

/* ───── Drug-cell stack: name + response rate + "See details" ─────
   The intervention cell rowspans the combo's three metric rows; its
   children stack vertically. The name keeps the small-caps headline
   treatment (rule 3 above); the rate (.tapp_stat) + the link button
   (.tapp_linkbtn) are framework primitives painted below. */
.tapp_matrix tbody td[data-col="drug"] {
    vertical-align: middle;
}
.tapp_matrix td[data-col="drug"] [data-drug-name] {
    display: block;
}

/* Bar graph — wrapper hosts a native <meter>. Plain HTML (no
   theme) gets the browser's default gauge for free; Drop overrides
   via ::-webkit-meter-* (Chromium/WebKit) and ::-moz-meter-bar
   (Firefox). The wrapper itself just owns layout + vertical center
   — no own background, so we don't double-track. */
.tapp_matrix [data-graph="bar"] {
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    /* Compact slot — only the 8px meter + a few px of breathing
       room. Keeps $ rows visually subordinate to the silhouette row. */
    height: 16px;
}
.tapp_matrix [data-graph="bar"] > meter {
    width: 100%;
    /* $ bar is intentionally THIN — the silhouette row is the
       headline; $ rows recede. */
    height: 8px;
    -webkit-appearance: none;
       -moz-appearance: none;
            appearance: none;
    /* No track background — only the filled portion paints, so the
       eye reads bar length directly without a grey "ghost" track
       suggesting an alternate scale. */
    background: transparent;
    border: 0;
    border-radius: 4px;
    overflow: hidden;
}
.tapp_matrix [data-graph="bar"] > meter::-webkit-meter-bar {
    background: transparent;
    border: 0;
    border-radius: 4px;
}
.tapp_matrix [data-graph="bar"] > meter::-webkit-meter-optimum-value,
.tapp_matrix [data-graph="bar"] > meter::-webkit-meter-suboptimum-value,
.tapp_matrix [data-graph="bar"] > meter::-webkit-meter-even-less-good-value {
    background: var(--tapp_brand-primary);
    border-radius: 4px;
    transition: width 180ms ease-out;
}
.tapp_matrix [data-graph="bar"] > meter::-moz-meter-bar {
    background: var(--tapp_brand-primary);
    border-radius: 4px;
}
/* Empty state — no <meter> emitted (cprEmitBar skips it). The
   wrapper renders nothing; '—' on the number column is the sole
   "no data" signal. */
.tapp_matrix [data-graph="bar"][data-empty="yes"] {
    background: transparent;
}

/* Silhouette graph — N <i> children, one per integer NNT/NTR unit
   (1 tile = 1 patient). Each <i> paints a single human-figure SVG via
   mask, tinted by brand-primary. The last <i> may carry inline opacity
   to render a fractional remainder. When the count exceeds
   SILHOUETTE_MAX_COUNT the wrapper gets data-overflow="yes" and a
   trailing ".tapp_silhouette_more" chip ("+Y") carries the capped tail
   instead of rescaling the tiles. */
.tapp_matrix [data-graph="silhouettes"] {
    flex-wrap: nowrap;
    gap: 3px;
    overflow: hidden;
    /* Headline visual — the slot grows tall enough to host the
       large silhouette tile. The NNT row's table-row height
       expands naturally to fit. No N-axis below this row (each
       silhouette already IS the unit), so the slot can claim the
       full visual budget for the icons. */
    height: 56px;
}
.tapp_matrix [data-graph="silhouettes"] > i {
    display: inline-block;
    /* Headline visual — sized to dominate the bar rows. The number
       cell still holds the exact figure; the silhouette is the
       "how many people" reading. Bumped after removing the N-axis
       (the axis labels used to share the slot). */
    width: 40px;
    height: 54px;
    /* The emoji 👤 ships as text content for plain-HTML readability;
       theme hides it (color: transparent) and paints a brand-tinted
       SVG mask over the box. Both approaches share the same flex tile. */
    color: transparent;
    font-size: 46px;
    line-height: 1;
    font-style: normal;
    background: var(--tapp_brand-primary);
    -webkit-mask: no-repeat center / contain url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='6' r='4'/><path d='M4 22 a8 8 0 0 1 16 0 Z'/></svg>");
            mask: no-repeat center / contain url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='6' r='4'/><path d='M4 22 a8 8 0 0 1 16 0 Z'/></svg>");
    flex: 0 0 auto;
}
/* "+Y" chip — the capped tail, shown as a count beside the last tile
   (1 tile = 1 patient preserved). Sits inline after the silhouettes,
   never shrinks, so the value cell stays in view. */
.tapp_matrix [data-graph="silhouettes"] > .tapp_silhouette_more {
    flex: 0 0 auto;
    margin-left: 6px;
    font-size: 15px;
    font-weight: 800;
    line-height: 1;
    color: var(--tapp_brand-primary);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* ── Reveal — left-to-right on render ─────────────────────────────
   Pattern follows the Drop launcher (.drop_curve_drop): pure
   transitions on the resting state + a state attribute that toggles
   the "from" → "to" delta. No @keyframes, no body-class gate — the
   framework's `body.tapp-no-animations * { transition: none !important }`
   rule disables every transition globally when the user turns
   animations off, so this paints at the final state instantly.

   How it fires:
   1. JS sets `data-fresh=""` on the graph slot AFTER appending the
      tiles / meter. While `data-fresh` is set, the override below
      paints the "from" state with `transition: none` so it lands
      instantly invisible / collapsed.
   2. JS removes `data-fresh` in the next animation frame
      (requestAnimationFrame). The rule no longer matches; the
      base transition kicks in and animates to the resting state.
   3. Per-tile transition-delay (inline-styled by JS for the
      silhouettes) cascades the appearance left-to-right. */

/* Silhouette resting state + transition (always applies). Slowed so the
   per-patient reveal cascade is legible (was 320ms — too fast to read). */
.tapp_matrix [data-graph="silhouettes"] > i {
    transition: opacity 700ms cubic-bezier(0.2, 0.7, 0.2, 1),
                transform 700ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
/* "From" — set instantly while data-fresh is active. */
.tapp_matrix [data-graph="silhouettes"][data-fresh] > i {
    opacity: 0;
    transform: translateX(-8px);
    transition: none;
}

/* Bar resting state + transition. Meter grows from the left edge,
   so transform-origin is set here once. */
.tapp_matrix [data-graph="bar"] > meter {
    transform-origin: left center;
    transition: transform 360ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.tapp_matrix [data-graph="bar"][data-fresh] > meter {
    transform: scaleX(0);
    transition: none;
}

/* ───── Endpoint "See details" comparison panel ─────────────────────
   Framework primitives (no module scope), reusable by any feature that
   needs a labeled horizontal-bar comparison: a split row (table | chart),
   a per-treatment color swatch keying table rows to bars, and the d3
   'barh' chart (tapp_barh*). */

/* Comparison table on the left, bar chart on the right; wrap on narrow. */
.tapp_split {
    display:     flex;
    flex-wrap:   wrap;
    align-items: flex-start;
    gap:         20px;
}
.tapp_split > .tapp_table  { flex: 0 0 auto; }
.tapp_split > [data-chart] { flex: 1 1 320px; min-width: 280px; }
/* When the split's children are [data-card] wrappers (chart card + table
   card, as in the CPR rates/cost sections), share the row evenly and wrap to
   stacked on narrow widths. */
.tapp_split > [data-card] { flex: 1 1 320px; min-width: 280px; }
/* A split COLUMN — flexes like a card but stacks its own children vertically
   (e.g. the $/Responder table with the NTR block beneath it, beside the
   graph). min-width:0 lets it shrink instead of forcing the split to WRAP
   (the inner table/silhouettes would otherwise push a large min-content). */
.tapp_split > .tapp_splitcol {
    flex:           1 1 320px;
    min-width:      0;
    display:        flex;
    flex-direction: column;
    gap:            6px;
}
/* The column's stacked children share its full width so the $/Responder table
   card and the NTR block line up (and the cross-tab table x-scrolls if wide).
   Drop the cards' own 8px margin — the column gap owns spacing — so the stack
   stays dense (maximize room for data). */
.tapp_splitcol > [data-card],
.tapp_splitcol > .tapp_ntr { width: 100%; margin: 0; }
/* Both tables fill the column width (the $/Responder cross-tab + the NTR
   matrix), so they read as one aligned stack. */
.tapp_splitcol .tapp_table,
.tapp_splitcol .tapp_matrix { width: 100%; }

/* A card holding a table scrolls horizontally rather than overflowing the
   layout — e.g. the cross-tab tables with many endpoint columns. (Card height
   is content-sized, so only the x-scrollbar appears.) */
[data-card]:has(> .tapp_table) { overflow: auto; }

/* Per-treatment color key — same hue as the matching bar. */
.tapp_swatch {
    display:        inline-block;
    width:          12px;
    height:         12px;
    border-radius:  3px;
    vertical-align: middle;
}
/* Module cover — a prominent title band above a module view's content
   (TApp.createCover). One per view; the feature supplies the title. */
.tapp_cover {
    margin:        0 0 16px;
    padding:       0 0 10px;
    border-bottom: 2px solid var(--tapp_brand-primary);
}
.tapp_cover_title {
    margin:      0;
    font-size:   1.5rem;
    font-weight: 700;
    color:       var(--tapp_theme-text);
}

/* Chart legend — a centered row of pills (color swatch + label), one per
   series. Sits above the chart and IS the series key. */
.tapp_legend {
    display:         flex;
    flex-wrap:       wrap;
    align-items:     center;
    justify-content: center;
    gap:             8px 14px;
    margin:          0 0 12px;
}
/* Lead-in label to the left of the legend pills (e.g. "Analyzing"). */
.tapp_legend_label {
    font-weight: 600;
    color:       var(--tapp_theme-text-muted);
}
.tapp_legend_pill {
    display:       inline-flex;
    align-items:   center;
    gap:           6px;
    padding:       3px 10px;
    border:        1px solid var(--tapp_theme-border);
    border-radius: 999px;
    font-size:     0.85em;
    white-space:   nowrap;
}
/* Height-capped chart wrapper — a fluid SVG fits WITHIN the section (scales
   down to honour max-height, keeping its aspect) so the module section
   doesn't grow to the chart's natural height. */
/* Chart flows with the container but never UP-scales past its natural size:
   the text lives in viewBox units, so scaling the SVG wider than its viewBox
   (720) would inflate the fonts. Cap the width at the viewBox width → at most
   1:1 (fonts at their authored size), shrinking down on narrower screens. */
.tapp_chartfit svg {
    display:   block;
    width:     100%;
    height:    auto;
    max-width: 720px;
    margin:    0 auto;   /* centre when the container is wider than the cap */
}
/* Title inside a chart card (above the chart): "Response rates" / "Cost per
   responder". */
.tapp_charttitle {
    margin:      0 0 8px;
    font-weight: 600;
    text-align:  center;
}
/* Fullscreen toggle overlaid on a chart card (top-right). Reuses the toolbar's
   fullscreen / fullscreen-exit corner glyphs. */
[data-card]:has(> .tapp_chartfs) { position: relative; }
.tapp_chartfs {
    position:            absolute;
    top:                 6px;
    right:               6px;
    width:               30px;
    height:              30px;
    padding:             0;
    border:              1px solid var(--tapp_theme-border);
    border-radius:       6px;
    background-color:    var(--tapp_theme-surface);
    background-repeat:   no-repeat;
    background-position: center;
    background-size:     17px;
    cursor:              pointer;
    opacity:             0.55;
    z-index:             2;
}
.tapp_chartfs:hover,
.tapp_chartfs:focus-visible { opacity: 1; }
.tapp_chartfs[data-icon="fullscreen"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M9 9 L3 3 M3 3 L8 3 M3 3 L3 8'/><path d='M15 9 L21 3 M21 3 L16 3 M21 3 L21 8'/><path d='M9 15 L3 21 M3 21 L8 21 M3 21 L3 16'/><path d='M15 15 L21 21 M21 21 L16 21 M21 21 L21 16'/></svg>");
}
.tapp_chartfs[data-icon="fullscreen-exit"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M3 3 L9 9 M9 9 L4 9 M9 9 L9 4'/><path d='M21 3 L15 9 M15 9 L20 9 M15 9 L15 4'/><path d='M3 21 L9 15 M9 15 L4 15 M9 15 L9 20'/><path d='M21 21 L15 15 M15 15 L20 15 M15 15 L15 20'/></svg>");
}

/* Sub-sub-section header (framework primitive) — one level below the section
   heading: a DIMMER brand band (6% vs the subsection's 10%) and SMALLER text.
   Any module can use .tapp_subhead. */
.tapp_subhead {
    margin:         4px 0 2px;
    padding:        0 9px;
    background:     color-mix(in srgb, var(--tapp_brand-primary) 6%, transparent);
    border-radius:  4px;
    font-family:    ui-sans-serif, system-ui, sans-serif;
    font-size:      11px;
    font-weight:    600;
    line-height:    1.55;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color:          var(--tapp_theme-text-muted);
}

/* NTR matrix: re-enable the column header (the matrix base hides thead) and
   paint it like the $/Responder table's dark band. */
.tapp_ntr .tapp_matrix thead { display: table-header-group; }
.tapp_ntr .tapp_matrix thead th {
    position:       static;
    background:     var(--tapp_theme-text);
    color:          var(--tapp_theme-text-inverted);
    text-align:     left;
    font-size:      11px;
    font-weight:    600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    padding:        6px 10px;
}
/* The silhouette column absorbs the slack so the figures get the room; the
   intervention + NTR columns stay tight (content width). */
.tapp_ntr .tapp_matrix td[data-col="graph"],
.tapp_ntr .tapp_matrix th[data-col="graph"] { width: 100%; }
.tapp_ntr .tapp_matrix td[data-col="name"]  { white-space: nowrap; }
/* Dense card — trim the matrix's generous padding + row gaps so the rows
   carry the data, not blank space. */
.tapp_ntr .tapp_matrix          { padding: 6px 12px; }
.tapp_ntr .tapp_matrix tbody td { padding-top: 1px; padding-bottom: 1px; }

/* Endpoint pager integrated INTO the NTR header band: ‹  NTR for …  › .
   The chevrons sit on the dark header, so they borrow currentColor. */
.tapp_ntrnav {
    display:     inline-flex;
    align-items: center;
    gap:         10px;
}
.tapp_ntrnav_btn {
    width:         19px;
    height:        19px;
    padding:       0;
    border:        1px solid currentColor;
    border-radius: 4px;
    background:    transparent;
    color:         inherit;
    font-size:     13px;
    line-height:   1;
    cursor:        pointer;
    opacity:       0.7;
}
.tapp_ntrnav_btn:hover,
.tapp_ntrnav_btn:focus-visible { opacity: 1; background: rgba(255, 255, 255, 0.16); }
.tapp_ntrnav_btn[hidden] { display: none; }

/* Clickable matrix cell (drill-down) — looks like the figure, reads as a link. */
.tapp_cellbtn {
    background:            none;
    border:               none;
    padding:              0;
    margin:               0;
    font:                 inherit;
    color:                inherit;
    cursor:               pointer;
    text-decoration:      underline;
    text-decoration-style: dotted;
    text-underline-offset: 2px;
}
.tapp_cellbtn:hover,
.tapp_cellbtn:focus-visible {
    text-decoration-style: solid;
    color:                 var(--tapp_brand-primary);
}

/* Cost build-up modal — regimen→brand hierarchy + roll-up. */
.tapp_buildup_regname  { font-weight: 600; }
.tapp_buildup_brandrow { cursor: pointer; }
.tapp_buildup_brandrow:hover > td {
    background: color-mix(in srgb, var(--tapp_brand-primary) 6%, transparent);
}
.tapp_buildup_brandrow[data-group-start] > td {
    border-top: 1px solid var(--tapp_theme-border);
}
.tapp_buildup_subtotal > td {
    font-weight: 600;
    border-top:  1px solid color-mix(in oklab, var(--tapp_theme-text) 25%, transparent);
}
.tapp_buildup_detailrow > td {
    padding:    2px 0 10px 28px;
    background: color-mix(in srgb, var(--tapp_brand-primary) 3%, transparent);
}
.tapp_buildup_roll {
    display:         flex;
    justify-content: space-between;
    gap:             16px;
    margin:          2px 0;
}
.tapp_buildup_roll[data-strong] { font-weight: 700; }
.tapp_buildup_roll [data-numeric] { font-variant-numeric: tabular-nums; }
/* Right-align + tabular numeric cells (the dialog's blanket left-align is
   scoped to [data-compare]; the build-up table isn't one). Magnitude-comparable
   figures: tabular-nums + the base mono face line up column-to-column. */
#tapp_dialog_modal .tapp_buildup [data-numeric] {
    text-align:           right;
    font-variant-numeric: tabular-nums;
}
/* The phase strip (regimen Gantt + pack markers) sits above the phase ledger
   in the expanded detail — give it breathing room. */
.tapp_buildup_detailrow .tapp_phasestrip_wrap { margin: 6px 0 14px; }

/* Silhouettes here are an ALTERNATIVE view, not the headline — render them
   smaller than the legacy results matrix (40px tile). */
.tapp_ntr .tapp_matrix [data-graph="silhouettes"] { height: 34px; gap: 2px; }
.tapp_ntr .tapp_matrix [data-graph="silhouettes"] > i { width: 24px; height: 32px; font-size: 28px; }
.tapp_ntr .tapp_matrix [data-graph="silhouettes"] > .tapp_silhouette_more { font-size: 12px; }

/* Fullscreen chart card — fill the screen + lift the chart size caps. */
[data-card]:fullscreen {
    background:      var(--tapp_theme-surface);
    padding:        3vh 3vw;
    display:        flex;
    flex-direction: column;
}
[data-card]:fullscreen .tapp_chartfit {
    max-height: none;
    flex:       1 1 auto;
    display:    flex;
    align-items: center;
}
[data-card]:fullscreen .tapp_chartfit svg { max-width: none; width: 100%; height: 100%; }
/* Back-to-top — framework-wide floating round button, bottom-right of the
   viewport, shown only once the feature section is scrolled down (JS toggles
   [hidden]). */
.tapp_backtotop {
    position:      fixed;
    bottom:        24px;
    right:         24px;
    z-index:       50;
    width:         40px;
    height:        40px;
    border-radius: 50%;
    border:        1px solid var(--tapp_theme-border);
    background:    var(--tapp_brand-primary);
    color:         #fff;
    font-size:     18px;
    line-height:   1;
    cursor:        pointer;
    box-shadow:    0 2px 10px var(--tapp_theme-shadow);
}
.tapp_backtotop:hover { filter: brightness(1.08); }
.tapp_backtotop[hidden] { display: none; }
/* Per-module branding mark — pinned top-right of the (non-scrolling)
   workspace, on the toolbar row. Top-LEFT toolbar vs top-RIGHT brand ⇒ no
   overlap; never scrolls or clips (it's not inside the scrolling section). */
#tapp_module_brand {
    position:       absolute;
    top:            calc(var(--drop-content-top) + 6px);
    right:          26px;
    z-index:        40;
    pointer-events: none;
    /* Subtle brand chip — surface + hairline border + pill radius, matching
       the toolbar's rounding/row height but NOT its sunken trench tint. */
    display:        inline-flex;
    align-items:    center;
    padding:        4px 12px;
    background:     var(--tapp_theme-surface);
    border:         1px solid var(--tapp_theme-border);
    border-radius:  9999px;
    box-shadow:     0 1px 3px var(--tapp_theme-shadow);
}
#tapp_module_brand[hidden] { display: none; }
#tapp_module_brand svg {
    display:    block;
    height:     28px;
    width:      auto;
    max-width:  220px;
}
/* Avoid the section-nav chevron pill: a multi-section module injects
   .drop_section_arrows_pill at the section's top-right (where the brand also
   sits), so shift the brand left of it ONLY when that pill is present. */
#tapp_workspace:has(section.tapp_feature_section:not([hidden]) > .drop_section_arrows_pill)
  #tapp_module_brand {
    right: 130px;
}
/* Module cover — a persistent title band above the swappable views. */
.tapp_cover {
    margin:         0 0 16px;
    padding-bottom: 10px;
    border-bottom:  1px solid var(--tapp_theme-border);
}
.tapp_cover_title {
    margin:      0;
    font-size:   1.5em;
    font-weight: 700;
}
/* Swappable view — Run fades the result view in, Erase the cover view.
   data-fresh pins opacity 0 (no transition) for one frame; clearing it
   transitions to 1. The hidden view is display:none (a swap, not a cross-fade). */
.tapp_view { transition: opacity 0.28s ease; }
.tapp_view[data-fresh] { opacity: 0; transition: none; }
body.tapp-no-animations .tapp_view { transition: none; }
/* Chart ⟷ table toggle: views flow to their content (no fixed height) — the
   layout resizes naturally on toggle for now. (Do NOT set `display` here: it
   would defeat the [hidden] attribute the JS uses to swap views.) */
.tapp_table[data-compare] th[data-col="swatch"],
.tapp_table[data-compare] td[data-col="swatch"] {
    width:      1%;
    text-align: center;
}
/* Non-sticky header here — the panel doesn't scroll, and static position
   avoids the toolbar-popover stacking issue the matrix table also opts
   out of. (The compare table keeps the framework's standard header band.) */
.tapp_table[data-compare] thead th { position: static; }

/* Zebra-stripe the share tables by group — every other drug / indication
   group carries [data-band], tinted with the active brand palette so its
   rows read as one block (rowspanned swatch/name cell included). */
.tapp_table[data-compare] tbody tr[data-band] > td {
    background: color-mix(in srgb, var(--tapp_brand-primary) 9%, transparent);
}

/* barh chart — currentColor drives text + axis + CI whisker; bars carry
   their own per-datum fill (set inline by the renderer). */
.tapp_barh       { color: var(--tapp_theme-text); max-width: 100%; height: auto; }
.tapp_barh_tick  { font-size: 10px; fill: color-mix(in oklab, var(--tapp_theme-text) 55%, transparent); }
.tapp_barh_grid  { opacity: 0.12; }
.tapp_barh_axis  { opacity: 0.35; }
.tapp_barh_label { font-size: 12px; }
.tapp_barh_value { font-size: 12px; font-weight: 700; }
.tapp_barh_ci    { opacity: 0.8; }
.tapp_barh_bar   { rx: 2; }

/* ───── Drug details: per-phase units table + catalog ────────────────
   Framework-class styling for the recovered indication/regimen detail.
   The phase table reuses .tapp_table[data-compare]; data-row/data-depth
   drive the phase→arm→brand hierarchy (indent + emphasis). */
.tapp_table[data-phase-table] tbody tr[data-row="phase"] > td {
    font-weight: 700;
    border-top: 1px solid var(--tapp_theme-border);
    padding-top: 8px;
}
/* Weighted-arm sub-header (e.g. "2.4 mg · 95%"). */
.tapp_table[data-phase-table] tbody tr[data-row="arm"] > td {
    font-weight: 600;
    padding-left: 16px;
    color: color-mix(in oklab, var(--tapp_theme-text) 80%, transparent);
}
/* Per-cohort leaf rows — SKU indented. */
.tapp_table[data-phase-table] tbody tr[data-row="leaf"] > td:first-child { padding-left: 16px; }
/* Indication subtotal — italic/muted ledger line. */
.tapp_table[data-phase-table] tbody tr[data-row="subtotal"] > td {
    font-style: italic;
    color: color-mix(in oklab, var(--tapp_theme-text) 65%, transparent);
}
.tapp_table[data-phase-table] tbody tr[data-row="subtotal"] > td:first-child { padding-left: 16px; text-align: right; }
/* Grand total. */
.tapp_table[data-phase-table] tbody tr[data-row="total"] > td {
    font-weight: 800;
    border-top: 2px solid var(--tapp_theme-border);
}
.tapp_table[data-phase-table] thead th { text-align: center; }
.tapp_table[data-phase-table] thead th[data-numeric] { text-align: right; }

/* Sub-section heading inside the detail panel. */
.tapp_subhead {
    margin: 14px 0 6px;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--tapp_brand-primary);
}

/* ====================================================================
   CPR drug-detail panel — a precision read-out, not a peer section.
   Signature element: the regimen ruler (phase strip). Type encodes
   ROLE — measurements ride the tabular mono face, labels ride the UI
   face — so the panel reads as an instrument, kept deliberately quiet
   around its one bold move. The .tapp_detailbody scope owns the
   compact type + vertical rhythm (6px unit).
   ==================================================================== */
.tapp_detailbody {
    --detail-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
                   "Liberation Mono", monospace;
    font-size:   12px;
    line-height: 1.45;
}
.tapp_detailbody .tapp_subhead { margin: 12px 0 4px; font-size: 10px; }
.tapp_detailbody .tapp_note    { margin: 8px 0; font-size: 11px; }

/* — Signature: the regimen ruler ————————————————————————————————
   Tiles flex-grow PROPORTIONALLY to phase duration (--phase-grow). A
   single brand hue with intensity RAMPED by phase order (--phase-mix,
   set in JS) reads as one regimen progressing through time, not the
   categorical rainbow a generic dashboard reaches for. The tiles sit on
   a thin brand baseline = the time axis; measurements (axis ends, dose
   window) ride the tabular mono face. */
/* Phase-strip — SVG timeline.  All tiles AND markers live in one SVG
   coordinate system (viewBox 0 0 1000 76, preserveAspectRatio="none"),
   eliminating the flex-vs-left:% coordinate mismatch of the old layout. */
.tapp_phasestrip_wrap { margin: 12px 0 6px; }
.tapp_phasestrip_svg  {
    display:  block;
    width:    100%;
    height:   76px;
    overflow: visible;
}

/* Phase tiles (SVG <rect>) */
.tapp_phasestrip_tile {
    fill: color-mix(in oklab, oklch(72% 0.13 var(--phase-hue, 266)) var(--phase-mix, 36%), transparent);
}
.tapp_phasestrip_tile-open {
    -webkit-mask-image: linear-gradient(to right, #000 86%, rgba(0,0,0,0.5));
            mask-image: linear-gradient(to right, #000 86%, rgba(0,0,0,0.5));
}
.tapp_phasestrip_tilelabel {
    font-weight: 600;
    font-size:   11px;
    fill:        var(--tapp_theme-text);
}
.tapp_phasestrip_tilewin {
    font-family:    var(--detail-mono);
    font-size:      10px;
    letter-spacing: 0.01em;
    fill:           var(--tapp_theme-text-muted);
}

/* Year gridlines (SVG <line>) */
.tapp_phasestrip_yearline {
    stroke:           color-mix(in oklab, var(--tapp_brand-primary) 50%, transparent);
    stroke-width:     1;
    stroke-dasharray: 4 3;
    pointer-events:   none;
}
.tapp_phasestrip_yearlabel {
    font-family: var(--detail-mono);
    font-size:   9px;
    fill:        var(--tapp_brand-primary);
}

/* Time axis (SVG <line> + <text>) */
.tapp_phasestrip_axisline {
    stroke:       color-mix(in oklab, var(--tapp_brand-primary) 30%, transparent);
    stroke-width: 1;
}
.tapp_axis_tick_mark {
    stroke:       color-mix(in oklab, currentColor 40%, transparent);
    stroke-width: 1;
}
.tapp_axis_label {
    font-family:    var(--detail-mono);
    font-size:      9.5px;
    letter-spacing: 0.02em;
    fill:           var(--tapp_theme-text-muted);
}

/* Pack-acquisition markers (SVG <text> with emoji + count <text>).
   One emoji per phase at the phase's first acquisition day. */
.tapp_phasestrip_marker { font-size: 11px; }
.tapp_marker_count {
    font-family: var(--detail-mono);
    font-size:   9px;
    font-weight: 600;
    fill:        var(--tapp_brand-primary);
}

/* — Resources-usage summary table (Drop-only treatment) ————————————
   Card-wide. No internal gridlines — only the rounded "around" border
   plus the single header/body separator survive. The header is demoted
   (small, muted, uppercase) and the values carry the weight; each
   resource column is prefixed with a glyph so the row reads as a
   scannable icon strip. */
.tapp_table[data-summary] {
    width:           100%;
    border:          1px solid var(--tapp_theme-border);
    border-radius:   8px;
    border-collapse: separate;
    border-spacing:  0;
    overflow:        hidden;        /* clip cells to the rounded corners */
}
.tapp_table[data-summary] th,
.tapp_table[data-summary] td {
    border:     0;                  /* drop horizontal lines + header underline */
    text-align: center;
    padding:    7px 10px;
}
.tapp_table[data-summary] th:first-child,
.tapp_table[data-summary] td:first-child { text-align: left; }   /* intervention label */
/* Vertical column separators only (no horizontal rules): a left border on
   every cell after the first, spanning header + body as a clean divider.
   Same intensity/colour as the rounded "around" border. */
.tapp_table[data-summary] th + th,
.tapp_table[data-summary] td + td {
    border-left: 1px solid var(--tapp_theme-border);
}

/* Demoted header (no underline — separators carry the column structure). */
.tapp_table[data-summary] thead th {
    background:     transparent;
    color:          var(--tapp_theme-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-size:      9px;
    font-weight:    600;
    white-space:    nowrap;
}
/* Bigger values. */
.tapp_table[data-summary] tbody td {
    font-size:   15px;
    line-height: 1.2;
    color:       var(--tapp_theme-text);
}
.tapp_table[data-summary] tbody [data-name] { font-weight: 600; }

/* Per-kind glyphs on the value cells (decorative; CSS-only, Drop-only).
   Shown even when the count is '—' so the column reads as "this resource
   type: none yet" for the not-yet-modeled kinds. */
.tapp_table[data-summary] tbody td[data-resource-kind]::before {
    margin-right: 5px;
    font-size:    0.9em;
}
.tapp_table[data-summary] tbody td[data-resource-kind="cost"]::before      { content: "🪙"; }
.tapp_table[data-summary] tbody td[data-resource-kind="drug"]::before      { content: "💊"; }
.tapp_table[data-summary] tbody td[data-resource-kind="device"]::before    { content: "💉"; }
.tapp_table[data-summary] tbody td[data-resource-kind="procedure"]::before { content: "🩺"; }

/* — Demoted disclosure (presentations; future price/blend editor) ——— */
.tapp_disclosure { margin-top: 10px; font-size: 11px; }
.tapp_disclosure > summary {
    cursor:         pointer;
    color:          var(--tapp_brand-accent-b, var(--tapp_brand-primary));
    font-weight:    600;
    letter-spacing: 0.02em;
    user-select:    none;
}

/* Section-level collapsible for the shares block. <summary class="tapp_subhead">
   inherits subhead styling; the ::before pyramid rotates open↔closed. */
.tapp_shares_toggle { margin-top: 16px; }
.tapp_shares_toggle > summary {
    cursor:      pointer;
    user-select: none;
    list-style:  none;
}
.tapp_shares_toggle > summary::-webkit-details-marker { display: none; }
.tapp_shares_toggle > summary.tapp_subhead::before,
.tapp_shares_toggle > summary.tapp_section_heading::before {
    content:      '▶ ';
    font-size:    0.75em;
    opacity:      0.55;
    margin-right: 2px;
}
.tapp_shares_toggle[open] > summary.tapp_subhead::before,
.tapp_shares_toggle[open] > summary.tapp_section_heading::before { content: '▼ '; }

/* Sectioned layout:
   `<tr data-row="section">` — full-width section header (regimen /
   presentations / outcomes group); tinted bg, emoji + label.
   `<tr data-row="outcome-header">` — per-outcome name, lighter
   tinted bg, sits inside the outcomes group.
   Detail rows (data-row="regimen|presentations|outcome") render
   one <td> per drug column. */
.tapp_table[data-transposed] tr[data-row="section"] > th {
    background:    color-mix(in oklab, var(--tapp_brand-primary) 14%, transparent);
    color:         var(--tapp_theme-text);
    text-align:    left;
    padding:       8px 12px;
    font-weight:   700;
    font-size:     0.95em;
    letter-spacing: 0.01em;
}
/* Inner wrapper carries the flex layout — keeping it off the <th>
   itself preserves `display: table-cell` so colspan extends the
   cell across all drug columns. */
.tapp_table[data-transposed] tr[data-row="section"] > th > [data-banner] {
    display:         flex;
    align-items:     center;
    justify-content: space-between;
    gap:             12px;
}
.tapp_table[data-transposed] tr[data-row="section"] > th [data-toggle-details] {
    flex:          0 0 auto;
    cursor:        pointer;
    background:    transparent;
    border:        1px solid var(--tapp_theme-border);
    border-radius: 4px;
    padding:       3px 10px;
    font:          inherit;
    font-size:     0.85em;
    font-weight:   500;
    color:         var(--tapp_theme-text);
}
.tapp_table[data-transposed] tr[data-row="section"] > th [data-toggle-details]:hover {
    background: color-mix(in oklab, var(--tapp_brand-primary) 8%, transparent);
}
/* Section-footer legend row — explains domain abbreviations used
   in the section's cells above (e.g. "IR: initial responders"
   under Outcomes). Footer convention: muted small italic,
   left-aligned to follow the reading flow. */
.tapp_table[data-transposed] tr[data-row="legend"] > td {
    padding:     6px 12px 4px;
    font-size:   0.8em;
    font-style:  italic;
    color:       var(--tapp_theme-text-muted);
    text-align:  left;
    border-top:  1px dashed color-mix(in oklab, var(--tapp_theme-border) 60%, transparent);
}
.tapp_table[data-transposed] tr[data-row="outcome-header"] > th {
    background:    color-mix(in oklab, var(--tapp_brand-primary) 6%, transparent);
    color:         var(--tapp_theme-text);
    text-align:    left;
    padding:       6px 12px;
    font-weight:   600;
    font-size:     0.9em;
}

/* Regimen detail-row cells anchor their content (axis + compact
   strip + detail strip) to the top edge. Default vertical-align:
   middle would re-center shorter columns when one drug's detail
   strip is taller than another's, breaking cross-drug alignment. */
.tapp_table[data-transposed] tr[data-row="regimen"] > td {
    vertical-align: top;
}

/* Regimen cell: phases laid out as a horizontal strip of "blocks"
   that read left-to-right as a treatment progression (loading →
   induction → maintenance). Each block carries a tinted brand
   background; phase name is prominent, timing window sits below
   the name in muted text, doses listed at the bottom. Reads as
   a compact mini-timeline without proportional duration math. */
/* Phases laid out as a horizontal flex strip with widths
   proportional to duration: each block's flex weight tracks
   --phase-grow (set by tmec.js from the phase's declared duration,
   with a 0.5 floor for zero-duration phases). align-items: stretch
   keeps every block the height of the tallest sibling. The cell
   scrolls horizontally only if intrinsic content somehow can't
   compress to share. */
.tapp_table[data-transposed] tr[data-row="regimen"] > td {
    overflow-x: auto;
}
/* Phase strips: shared flex/proportional layout for both the
   compact strip (name-only, always visible) and the detail strip
   (full info inside <details>). Each phase <li> in either strip
   takes a width proportional to --phase-grow and a tint set by
   --phase-mix — so the two strips line up column-for-column. */
.tapp_table[data-transposed] tr[data-row="regimen"] td [data-strip] {
    display:        flex;
    flex-direction: row;
    flex-wrap:      nowrap;
    gap:            6px;
    padding:        0;
    margin:         0;
    list-style:     none;
    align-items:    stretch;
}
.tapp_table[data-transposed] tr[data-row="regimen"] td [data-strip] > li {
    flex:           var(--phase-grow, 1) 1 0;
    min-width:      0;
    padding:        6px 8px;
    /* Dashboard-categorical phase tile: hue comes from
       --phase-hue (set per phase index by tmec.js, evenly spread
       around the OKLCH wheel from the brand anchor); fixed L + C
       keep all phase tiles perceptually equal-weight. Pastel L
       (~0.7) so the mid-opacity fill reads as a clear category
       color without burying the dark text on top. */
    background:     color-mix(in oklab, oklch(70% 0.16 var(--phase-hue, 266)) var(--phase-mix, 38%), transparent);
    border-radius:  4px;
    font-size:      0.9em;
    line-height:    1.3;
    overflow:       hidden;
}

/* Compact strip: phase name (prominent) + duration window (muted,
   smaller) stacked vertically. Both ellipsis-clip when the column
   is too narrow; full name lives in the title attr for hover. */
.tapp_table[data-transposed] tr[data-row="regimen"] td [data-strip="compact"] > li > [data-name] {
    display:       block;
    font-weight:   600;
    color:         var(--tapp_theme-text);
    white-space:   nowrap;
    overflow:      hidden;
    text-overflow: ellipsis;
}
.tapp_table[data-transposed] tr[data-row="regimen"] td [data-strip="compact"] > li > [data-window] {
    display:       block;
    font-size:     0.85em;
    color:         var(--tapp_theme-text-muted);
    white-space:   nowrap;
    overflow:      hidden;
    text-overflow: ellipsis;
}

/* Detail strip = a phase table (one row per phase, columns
   phase | duration | doses). Hidden by default; revealed for ALL
   drug columns at once when the Regimen section's banner toggle
   sets `[data-show-details]` on the outer condition table — single
   source of truth keeps cross-drug row heights aligned. */
.tapp_table[data-transposed] tr[data-row="regimen"] td > table[data-strip="detail"] {
    display:         none;
    margin-top:      6px;
    width:           100%;
    border-collapse: collapse;
    font-size:       0.85em;
}
.tapp_table[data-transposed][data-show-details] tr[data-row="regimen"] td > table[data-strip="detail"] {
    display: table;
}
/* Header row — subtle muted band, no inverted dark paint here
   (we're nested inside a regimen cell; the outer table's thead
   already provides the strong band, and a second one would be
   visually loud). */
.tapp_table[data-transposed] tr[data-row="regimen"] td > table[data-strip="detail"] thead th {
    background:     transparent;
    color:          var(--tapp_theme-text-muted);
    text-transform: none;
    letter-spacing: 0;
    font-size:      inherit;
    font-weight:    600;
    text-align:     left;
    padding:        4px 8px;
    border-bottom:  1px solid var(--tapp_theme-border);
}
/* Each phase row carries the --phase-mix tint set by JS so the
   row colors match the compact strip blocks above. The data-open
   marker tags the open-ended phase (currently visual-only). */
.tapp_table[data-transposed] tr[data-row="regimen"] td > table[data-strip="detail"] tbody tr {
    /* Mirrors the compact-strip tile paint above (same L, C, hue,
       mix) so the open-details rows read as the same phase blocks
       expanded — column-for-column hue alignment, not a different
       color family. */
    background: color-mix(in oklab, oklch(70% 0.16 var(--phase-hue, 266)) var(--phase-mix, 38%), transparent);
}
.tapp_table[data-transposed] tr[data-row="regimen"] td > table[data-strip="detail"] tbody th,
.tapp_table[data-transposed] tr[data-row="regimen"] td > table[data-strip="detail"] tbody td {
    padding:        4px 8px;
    vertical-align: top;
    text-align:     left;
    border-bottom:  1px solid color-mix(in oklab, var(--tapp_theme-border) 40%, transparent);
}
.tapp_table[data-transposed] tr[data-row="regimen"] td > table[data-strip="detail"] tbody th[scope="row"] > [data-name] {
    font-weight: 600;
    color:       var(--tapp_theme-text);
}
.tapp_table[data-transposed] tr[data-row="regimen"] td > table[data-strip="detail"] tbody td > [data-window] {
    color: var(--tapp_theme-text-muted);
}
/* Multi-dose cell renders an unstyled <ul>; single-dose is a
   plain text node. */
.tapp_table[data-transposed] tr[data-row="regimen"] td > table[data-strip="detail"] tbody td > ul {
    padding:    0 0 0 16px;
    margin:     0;
}

/* Timeline axis: thin horizontal scale sitting above the phase
   strip, labelling the model horizon (stubbed at "1 año" in JS).
   Plain horizontal rule with a centered label "anchored" to it via
   a small inset background patch — reads as a Gantt-like time
   ruler without needing tick marks (the phase blocks themselves
   are the proportional intervals). */
.tapp_table[data-transposed] tr[data-row="regimen"] td > [data-timeline-axis] {
    position:      relative;
    border-top:    1px solid var(--tapp_theme-border);
    height:        12px;
    margin-bottom: 4px;
}
.tapp_table[data-transposed] tr[data-row="regimen"] td > [data-timeline-axis] > span {
    position:    absolute;
    top:         -0.6em;
    left:        50%;
    transform:   translateX(-50%);
    background:  var(--tapp_theme-surface);
    padding:     0 6px;
    font-size:   0.75em;
    color:       var(--tapp_theme-text-muted);
}

/* Outcome sub-header (`tr[data-row="outcome-header"]`) — the four
   identity axes now arrive as separate spans (data-outcome /
   data-time / data-analysisset / data-subgroup) so each is painted
   with its own weight + size instead of one em-dash string. */
.tapp_table[data-transposed] tr[data-row="outcome-header"] > th > [data-outcome] {
    font-weight: 700;
    color:       var(--tapp_theme-text);
    margin-right: 8px;
}
.tapp_table[data-transposed] tr[data-row="outcome-header"] > th > [data-time] {
    font-size:    0.85em;
    color:        var(--tapp_theme-text-muted);
    margin-right: 8px;
}
.tapp_table[data-transposed] tr[data-row="outcome-header"] > th > [data-analysisset],
.tapp_table[data-transposed] tr[data-row="outcome-header"] > th > [data-subgroup] {
    display:       inline-block;
    font-size:     0.75em;
    font-weight:   600;
    color:         var(--tapp_theme-text-muted);
    background:    color-mix(in oklab, var(--tapp_brand-primary) 10%, transparent);
    padding:       1px 6px;
    border-radius: 3px;
    margin-right:  4px;
}

/* Per-outcome cells: when a (drug × endpoint) pair has multiple
   protocols, records render as side-by-side sub-columns. Top-
   aligned + vertical divider between siblings. */
.tapp_table[data-transposed] tr[data-row="outcome"] > td {
    vertical-align: top;
}
.tapp_table[data-transposed] tr[data-row="outcome"] td > ol {
    display:        flex;
    flex-direction: row;
    gap:            12px;
    padding:        0;
    margin:         0;
    list-style:     none;
    align-items:    stretch;
}
.tapp_table[data-transposed] tr[data-row="outcome"] td > ol > li {
    flex:    1 1 0;
    min-width: 0;
}
.tapp_table[data-transposed] tr[data-row="outcome"] td > ol > li:not(:last-child) {
    border-right:  1px solid var(--tapp_theme-border);
    padding-right: 12px;
}

/* Per-record metadata header — protocol + IR datum. Protocol is
   the prominent identifier; IR (initial-responder rate) is a
   protocol-level datum, NOT a clinical rate, so it sits ALONGSIDE
   the protocol as metadata (smaller, muted) rather than mixed
   into the rate lines below. */
.tapp_table[data-transposed] tr[data-row="outcome"] td > ol > li > header[data-meta] {
    display:        flex;
    flex-wrap:      wrap;
    align-items:    baseline;
    gap:            6px;
    margin-bottom:  4px;
    padding-bottom: 2px;
    border-bottom:  1px dashed color-mix(in oklab, var(--tapp_theme-border) 60%, transparent);
}
.tapp_table[data-transposed] tr[data-row="outcome"] td > ol > li > header[data-meta] > [data-protocol] {
    font-weight: 600;
    color:       var(--tapp_theme-text);
}
.tapp_table[data-transposed] tr[data-row="outcome"] td > ol > li > header[data-meta] > [data-gate] {
    font-size:     0.8em;
    color:         var(--tapp_theme-text-muted);
    background:    color-mix(in oklab, var(--tapp_brand-primary) 8%, transparent);
    padding:       1px 6px;
    border-radius: 3px;
    font-weight:   500;
}

/* Rates table — per-record table inside each outcome cell:
   rows = measurements (arm-alone + one per armDiff baseRef),
   columns = denominator frames (all / IR). Reported frame cell
   holds the trial value; the other column derives from P_init
   when available and gets [data-derived] (italic + faded) so the
   modeler can tell which value was reported vs derived here.
   The arm-alone row is prominent (the absolute / no-comparator
   measurement); arm-vs-* rows are muted (secondary increments). */
.tapp_table[data-transposed] tr[data-row="outcome"] td > ol > li > table[data-rates] {
    border-collapse: collapse;
    margin-top:      2px;
    font-size:       0.9em;
    width:           auto;
}
.tapp_table[data-transposed] tr[data-row="outcome"] td > ol > li > table[data-rates] thead th {
    text-align:     center;
    font-size:      0.8em;
    font-weight:    600;
    color:          var(--tapp_theme-text-muted);
    padding:        2px 8px;
    background:     transparent;
    text-transform: none;
    letter-spacing: 0;
    border-bottom:  1px solid var(--tapp_theme-border);
}
.tapp_table[data-transposed] tr[data-row="outcome"] td > ol > li > table[data-rates] tbody th[scope="row"] {
    text-align:  left;
    font-weight: 500;
    color:       var(--tapp_theme-text);
    padding:     2px 12px 2px 0;
    background:  transparent;
    white-space: nowrap;
}
.tapp_table[data-transposed] tr[data-row="outcome"] td > ol > li > table[data-rates] tbody tr[data-line="arm-alone"] > th[scope="row"] {
    font-weight: 600;
}
.tapp_table[data-transposed] tr[data-row="outcome"] td > ol > li > table[data-rates] tbody td {
    padding:        2px 8px;
    background:     transparent;
    text-align:     right;
    white-space:    nowrap;
    font-variant-numeric: tabular-nums;
    border-bottom:  none;
}
.tapp_table[data-transposed] tr[data-row="outcome"] td > ol > li > table[data-rates] tbody tr[data-line^="arm-vs-"] {
    color: var(--tapp_theme-text-muted);
}
.tapp_table[data-transposed] tr[data-row="outcome"] td > ol > li > table[data-rates] tbody td[data-derived] {
    font-style: italic;
    opacity:    0.75;
}
/* Within each rate cell, stack the value above the CI annotation:
   value normal-size, CI below in smaller / faded muted text (same
   subordinate-annotation treatment as the regimen phase window or
   the protocol-header gate datum). text-align:right on the td
   cascades into both blocks. */
.tapp_table[data-transposed] tr[data-row="outcome"] td > ol > li > table[data-rates] tbody td > [data-value] {
    display: block;
}
.tapp_table[data-transposed] tr[data-row="outcome"] td > ol > li > table[data-rates] tbody td > [data-ci] {
    display:     block;
    font-size:   0.8em;
    line-height: 1.15;
    color:       var(--tapp_theme-text-muted);
}

/* Brand-color gradient across the "aggregate" rows: leaf data rows,
   subtotal row, cumulative total row — at 50% / 75% / 100% brand alpha
   respectively. The font flips to text-inverted because at full brand
   the regular text-color loses contrast (works in both light + dark
   modes since the brand colour is constant and text-inverted always
   sits on the opposite end of the surface's contrast scale).
   The bottom-right Σ cell of the cumulative row breaks out into the
   "header" treatment — see the override below.

   `tbody tr[data-leaf="true"]` is scoped to tbody because the total
   rows in tfoot also carry data-leaf="true". */
.tapp_table tbody tr[data-leaf="true"] > td {
    background: color-mix(in oklab, var(--tapp_brand-primary) 50%, transparent);
    color: var(--tapp_theme-text-inverted);
    font-weight: 700;
}
/* Bumped specificity: the generic `.tapp_table tfoot td` rule
   above (sticky-pin + surface bg) was outranking the plain
   `tr[data-total]--*` selectors below and washing them out
   to surface. Prepending `.tapp_table tfoot` flips specificity. */
.tapp_table tfoot tr[data-total="delta"] > td {
    background: color-mix(in oklab, var(--tapp_brand-primary) 75%, transparent);
    color: var(--tapp_theme-text-inverted);
    border-top: 2px solid var(--tapp_theme-border);
    border-bottom: 1px solid color-mix(in oklab, var(--tapp_theme-text-inverted) 25%, transparent);
    padding-top: 8px;
    padding-bottom: 6px;
    font-weight: 700;
}
.tapp_table tfoot tr[data-total="cum"] > td {
    background: var(--tapp_brand-primary);
    color: var(--tapp_theme-text-inverted);
    border-top: none;
    border-bottom: none;
    padding-top: 6px;
    padding-bottom: 6px;
    font-weight: 700;
}
/* Bottom-right corner — the table's headline cell. Header-styled
   inverted band (--tapp_theme-text → bg, --tapp_theme-text-inverted →
   fg). Mirrors the header band: uppercase, tracked, smaller font. */
.tapp_table tfoot tr[data-total="cum"] > td[data-col="sum"] {
    background: var(--tapp_theme-text);
    color: var(--tapp_theme-text-inverted);
    font-size: 11px;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}
/* Strikethrough on overridden values inside any brand-bg row picks
   up the inverted text colour so it stays visible. */
.tapp_table tbody tr[data-leaf="true"] .tapp_value_strike,
tr[data-total] .tapp_value_strike {
    color: var(--tapp_theme-text-inverted);
}

/* tcli-epi sub-section block headings now flow through the
   framework rule above — sub-sections in the template carry
   class="tapp_section" + h3.tapp_section_heading. The legacy
   #tcli_epi_workspace h3 rule that lived here was removed when the
   migration landed. */

/* Legends strip — heading + comma-separated definitions inline. The
   <ul> + <li>s render inline so the whole thing reads as one
   sentence: "Legends: ▲ growth, ● prevalence, …". */
#tcli_epi_legends {
    margin-top:  12px;
    line-height: 1.7;
    font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
    font-size:   13px;
    color:       var(--tapp_theme-text);
}
/* Inline heading inside the legend strip — keep the caption look
   but strip the framework's full-width band styling. Specificity
   bumped (added #tapp_workspace + section.tapp_feature_section)
   to win over the framework rule's 1,4,1 — now reads 2,2,2. */
#tapp_workspace section.tapp_feature_section #tcli_epi_legends > h3 {
    display:        inline;
    margin:         0 6px 0 0;
    padding:        0;
    background:     none;
    border-radius:  0;
    font-family:    inherit;
    font-size:      inherit;
    font-weight:    600;
    letter-spacing: normal;
    text-transform: none;
    color:          inherit;
}
#tcli_epi_legends h3::after { content: ":"; }
#tcli_epi_legends ul,
#tcli_epi_legends li { display: inline; }
#tcli_epi_legends ul { margin: 0; padding: 0; list-style: none; }
#tcli_epi_legends li:not(:last-child)::after { content: ", "; }

/* tapp_error_card — diagnostic / status card.
   Centred (max-width 580px) when used as a feature-level empty/error state.
   Inline when used as a status message inside a panel section (no max-width
   override needed — the panel constrains width naturally).
   data-tone: error | info | warning | success
   Inner structure:
     .tapp_error_card_title    — emphasized main message
     .tapp_error_card_log      — inset detail box (error list or hint)
     .tapp_error_card_log_label — small uppercase label above the list
     .tapp_error_log_list      — <ol> of monospace error lines        */
.tapp_error_card {
    max-width: 580px;
    margin: 48px auto;
    border: 1px solid;
    border-radius: 8px;
    padding: 20px 24px;
}
.tapp_error_card[data-tone="error"] {
    border-color: var(--tapp_status-error);
    background:   var(--tapp_status-error-light);
}
.tapp_error_card[data-tone="info"] {
    border-color: var(--tapp_status-info);
    background:   var(--tapp_status-info-light);
}
.tapp_error_card[data-tone="warning"] {
    border-color: var(--tapp_status-warning);
    background:   var(--tapp_status-warning-light);
}
.tapp_error_card[data-tone="success"] {
    border-color: var(--tapp_status-success);
    background:   var(--tapp_status-success-light);
}
.tapp_error_card_title {
    font-size:   15px;
    font-weight: 600;
    color:       var(--tapp_theme-text);
    margin:      0 0 14px;
}
.tapp_error_card_log {
    background:    var(--tapp_theme-surface);
    border:        1px solid var(--tapp_theme-border);
    border-radius: 4px;
    padding:       10px 14px;
    max-height:    180px;
    overflow-y:    auto;
    font-size:     13px;
    color:         var(--tapp_theme-text-muted);
}
.tapp_error_card_log p { margin: 0; }
.tapp_error_card_log_label {
    font-size:      11px;
    font-weight:    700;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color:          var(--tapp_theme-text-muted);
    margin:         0 0 8px;
}
.tapp_error_card[data-tone="error"] .tapp_error_card_log_label {
    color: var(--tapp_status-error);
}
.tapp_error_log_list {
    margin:      0;
    padding:     0 0 0 1.4em;
    list-style:  decimal;
    font-family: ui-monospace, "Cascadia Code", "Fira Mono", monospace;
    font-size:   12px;
    color:       var(--tapp_theme-text);
    line-height: 1.6;
}

/* References — framework primitive (TApp.references). Bibliography
   list rendered from <teff:gen>/<metadata>/<references>; shared by
   every feature (3epi, cpr, …). The .tapp_references* classes are the
   styling contract — the heading rides the standard nested
   .tapp_section_heading band. Only typography tightening lives here;
   the body inherits the workspace font. */
.tapp_references {
    font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
    font-size:   13px;
    line-height: 1.5;
    color:       var(--tapp_theme-text);
}
.tapp_references_list {
    margin:     6px 0 0;
    padding:    0 0 0 1.6em;        /* room for the decimal markers */
    list-style: decimal;
}
.tapp_references_item { margin: 0; padding: 0; }
.tapp_references_item + .tapp_references_item { margin-top: 0.25em; }
.tapp_references_item cite { font-style: italic; }
.tapp_references_item a    { color: var(--tapp_brand-primary); }
.tapp_table [data-col="rate"] {
    color: var(--tapp_theme-text-muted);
    font-variant-numeric: tabular-nums;
}

/* ====================================================================
   tapp_pill — framework primitive (see doc/DEVELOPER_GUIDE.md →
   "Framework UI primitives"). Inline-flow rounded chip with a
   tone-vocabulary attribute (data-tone). Drop owns both the
   structural shape AND the per-tone tint here.
   ==================================================================== */
.tapp_pill {
    display:        inline-block;
    min-width:      1.4em;
    text-align:     center;
    padding:        0 6px;
    margin-right:   4px;
    border-radius:  4px;
    background:     rgba(0, 0, 0, 0.10);
    font-weight:    600;
    font-size:      0.85em;
    line-height:    1.5;
    vertical-align: baseline;
}
.tapp_pill[data-tone="success"] { background: rgba( 39, 174,  96, 0.18); color: #1e8449; }
.tapp_pill[data-tone="info"]    { background: rgba( 41, 128, 185, 0.18); color: #1f618d; }
.tapp_pill[data-tone="warning"] { background: rgba(243, 156,  18, 0.20); color: #b9770e; }
.tapp_pill[data-tone="accent"]  { background: rgba(155,  89, 182, 0.18); color: #7d3c98; }
.tapp_pill[data-tone="neutral"] { background: rgba(  0,   0,   0, 0.08); color: inherit;  }
.tapp_pill[data-tone="error"]   { background: rgba(220,  38,  38, 0.12); color: #dc2626;   }

/* ── Percentage-change badge ──────────────────────────────────────────────
   [data-pct="up"]  green badge for a positive price change
   [data-pct="dn"]  red badge for a negative price change                  */
[data-pct] {
    display: inline-block;
    font-size: 0.78em;
    font-weight: 600;
    padding: 0.1em 0.35em;
    border-radius: 3px;
    margin-left: 0.3em;
    white-space: nowrap;
}
[data-pct="up"] { background: rgba( 39, 174,  96, 0.14); color: #1e8449; }
[data-pct="dn"] { background: rgba(220,  38,  38, 0.12); color: #c0392b; }

/* ── Form row ─────────────────────────────────────────────────────────────
   [data-form-row]  flex container: label + input(s) + optional button
                    on one line, aligned baseline.                         */
[data-form-row] {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    flex-wrap: wrap;
}
[data-form-row] > label {
    white-space: nowrap;
    font-size: 0.875rem;
    color: var(--tapp_text-muted, inherit);
    flex-shrink: 0;
}
[data-form-row] > input,
[data-form-row] > select {
    flex: 1 1 auto;
    min-width: 0;
}

/* ── Scroll container ─────────────────────────────────────────────────────
   data-scroll       natural height, overflow-y scroll
   data-scroll="sm"  ~200 px cap — short pick-lists / cascade levels
   data-scroll="md"  ~260 px cap — medium lists                           */
[data-scroll]      { overflow-y: auto; }
[data-scroll="sm"] { max-height: 12.5rem; }
[data-scroll="md"] { max-height: 16.25rem; }

/* Clickable / muted table row states */
.tapp_table tbody tr[data-action] { cursor: pointer; }
.tapp_table tbody tr[data-muted]  { opacity: 0.45; }

/* Inline monospace identifier */
.tapp_code {
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
    font-size:   0.78em;
    user-select: all;
}

/* tapp_linkbtn inside a <td> — inline reset */
td > .tapp_linkbtn { display: inline; width: auto; margin-top: 0; text-align: inherit; }

/* Inline copy-to-clipboard button — shows opaque IDs without cluttering the cell */
.tapp_copy_btn {
    display: inline-block;
    width: 16px; height: 16px;
    padding: 0; border: none;
    background: transparent url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23aaa' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect width='14' height='14' x='8' y='8' rx='2' ry='2'/><path d='M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2'/></svg>") center/14px no-repeat;
    cursor: pointer;
    vertical-align: middle;
    flex-shrink: 0;
}
.tapp_copy_btn:hover {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect width='14' height='14' x='8' y='8' rx='2' ry='2'/><path d='M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2'/></svg>");
}
.tapp_copy_btn[data-copied] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2322c55e' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><path d='M20 6 9 17l-5-5'/></svg>");
}

/* Danger tone for tapp_linkbtn */
.tapp_linkbtn[data-tone="danger"] { color: var(--tapp_status-error); }

/* ====================================================================
   Table — hierarchy indentation, override-value strike, inactive cue.
   Structural data-level hooks live in tcli.css; the visible indent
   amounts + decorations are theme-owned.
   ==================================================================== */
.tapp_table tr[data-level="0"] > td:first-child { padding-left: 0;     }
.tapp_table tr[data-level="1"] > td:first-child { padding-left: 16px;  }
.tapp_table tr[data-level="2"] > td:first-child { padding-left: 32px;  }
.tapp_table tr[data-level="3"] > td:first-child { padding-left: 48px;  }
.tapp_table tr[data-level="4"] > td:first-child { padding-left: 64px;  }
.tapp_table tr[data-level="5"] > td:first-child { padding-left: 80px;  }
.tapp_table tr[data-level="6"] > td:first-child { padding-left: 96px;  }
.tapp_table tr[data-level="7"] > td:first-child { padding-left: 112px; }

.tapp_table.tapp_value_strike {
    text-decoration: line-through;
    opacity:         0.55;
    margin-right:    0.3em;
}
.tapp_table tr[data-active="no"] { opacity: 0.55; }
.tapp_table tr[data-active="no"] > td:first-child { text-decoration: line-through; }

/* ====================================================================
   Chart inactive cue + results-mode label sizing. Mirrors the table.
   ==================================================================== */
.tapp_flowchart_node[data-active="no"] { opacity: 0.55; }
.tapp_flowchart_node[data-active="no"] .tapp_flowchart_node_label { text-decoration: line-through; }
[data-tapp-chart-mode="results"] .tapp_flowchart_edge_label_text tspan:not(:first-of-type) {
    font-size: 0.8em;
}

/* ====================================================================
   Flowchart reveal animation — cascade by depth.
   charts.js stamps the chart root with
   data-tapp-chart-reveal="initial" on opts.animate=true renders,
   then flips to "revealed" on the next paint frame. We hide nodes
   + links + edge labels in the "initial" state and transition them
   to full opacity (and slide-in from above for nodes) on revealed,
   staggered by data-depth so the cascade paints level-by-level —
   pop first, demos next, leaves last.
   The dual-g pattern in charts.js (outer <g> holds the SVG
   `transform` attribute for layout, inner .tapp_flowchart_node is
   the CSS animation target) is what lets the slide-in's CSS
   `transform: translateY(-8px)` work without snapping the node to
   the SVG origin.
   When the user mutes animations, base.css zeros all transitions
   AND charts.js skips the initial→revealed dance entirely, so the
   chart paints in its final state with no movement.
   ==================================================================== */
.tapp_flowchart_node,
.tapp_flowchart_link,
.tapp_flowchart_edge_label {
    transition: opacity 350ms ease, transform 350ms ease;
}
[data-tapp-chart-reveal="initial"] .tapp_flowchart_node,
[data-tapp-chart-reveal="initial"] .tapp_flowchart_link,
[data-tapp-chart-reveal="initial"] .tapp_flowchart_edge_label {
    opacity: 0;
}
[data-tapp-chart-reveal="initial"] .tapp_flowchart_node {
    transform: translateY(-8px);
}
/* Depth-staggered delays. Nodes settle at multiples of 200ms;
   edges arrive 100ms before the node at the same depth so the
   line draws into a still-empty target — feels like the cohort
   is flowing toward the cell about to appear. */
.tapp_flowchart_node[data-depth="0"] { transition-delay:    0ms; }
.tapp_flowchart_node[data-depth="1"] { transition-delay:  200ms; }
.tapp_flowchart_node[data-depth="2"] { transition-delay:  400ms; }
.tapp_flowchart_node[data-depth="3"] { transition-delay:  600ms; }
.tapp_flowchart_node[data-depth="4"] { transition-delay:  800ms; }
.tapp_flowchart_node[data-depth="5"] { transition-delay: 1000ms; }
.tapp_flowchart_node[data-depth="6"] { transition-delay: 1200ms; }
.tapp_flowchart_node[data-depth="7"] { transition-delay: 1400ms; }
.tapp_flowchart_link[data-depth="1"],
.tapp_flowchart_edge_label[data-depth="1"] { transition-delay:  100ms; }
.tapp_flowchart_link[data-depth="2"],
.tapp_flowchart_edge_label[data-depth="2"] { transition-delay:  300ms; }
.tapp_flowchart_link[data-depth="3"],
.tapp_flowchart_edge_label[data-depth="3"] { transition-delay:  500ms; }
.tapp_flowchart_link[data-depth="4"],
.tapp_flowchart_edge_label[data-depth="4"] { transition-delay:  700ms; }
.tapp_flowchart_link[data-depth="5"],
.tapp_flowchart_edge_label[data-depth="5"] { transition-delay:  900ms; }
.tapp_flowchart_link[data-depth="6"],
.tapp_flowchart_edge_label[data-depth="6"] { transition-delay: 1100ms; }
.tapp_flowchart_link[data-depth="7"],
.tapp_flowchart_edge_label[data-depth="7"] { transition-delay: 1300ms; }

/* ====================================================================
   Edit dialog — cell padding/alignment + sum/invalid/inactive cues.
   Scoped inside #tapp_dialog_modal to the tapp_table primitive; cues
   driven by [data-invalid], [data-active="no"], <tfoot> + scope="row"
   semantics. No module-specific classes.
   ==================================================================== */
#tapp_dialog_modal .tapp_table { margin: 8px 0; }
#tapp_dialog_modal .tapp_table th,
#tapp_dialog_modal .tapp_table td {
    padding:        4px 8px;
    vertical-align: middle;
    text-align:     left;
}
/* Comparison tables ([data-compare], e.g. the endpoint detail) keep their
   numeric-cell alignment inside the dialog — the blanket left-align above
   (ID specificity) would otherwise clobber [data-numeric]. Scoped to
   [data-compare] so the edit/ledger dialog tables are untouched. */
#tapp_dialog_modal .tapp_table[data-compare] [data-numeric] { text-align: right; }
#tapp_dialog_modal .tapp_table[data-compare] [data-numeric="center"] { text-align: center; }
#tapp_dialog_modal .tapp_table tfoot td { border-top: 1px solid currentColor; }
#tapp_dialog_modal .tapp_table tfoot th[scope="row"] { font-weight: 600; }
#tapp_dialog_modal .tapp_table tfoot td[data-col="sum"] {
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
}
/* Invalid markers — themes paint via data-invalid on cells or inputs.
   The attribute selector is generic (any module can use it). */
[data-invalid] { color: #c0392b; }
input[data-invalid] {
    border-color: #c0392b;
    background:   rgba(192, 57, 43, 0.08);
}
/* Inactive rows in the override-edit dialog dim + strike the row
   header (scope="row" th) to mirror the chart/table inactive cue. */
#tapp_dialog_modal .tapp_table tr[data-active="no"] th[scope="row"] {
    text-decoration: line-through;
    opacity:         0.6;
}
#tapp_dialog_modal .tapp_table tr[data-active="no"] td input[type="number"] {
    opacity: 0.75;
}

/* Tree flowchart — leaves emphasized as solid black with white text.
   Other nodes (root, demo, intermediate states) keep the framework's
   structural defaults (outline-only) in Drop; styling them is a
   separate concern. */
/* Hierarchy fade — chart node fills mirror the table's tiered brand
   tint. Each depth step adds ~8% brand-primary mix; leaves snap to
   full brand with inverted text. data-depth is emitted per node by
   the flowchart renderer (charts.js). */
.tapp_flowchart_node[data-depth="0"] .tapp_flowchart_node_rect { fill: transparent; }
.tapp_flowchart_node[data-depth="1"]:not(.tapp_flowchart_node--leaf) .tapp_flowchart_node_rect { fill: color-mix(in srgb, var(--tapp_brand-primary)  8%, transparent); }
.tapp_flowchart_node[data-depth="2"]:not(.tapp_flowchart_node--leaf) .tapp_flowchart_node_rect { fill: color-mix(in srgb, var(--tapp_brand-primary) 16%, transparent); }
.tapp_flowchart_node[data-depth="3"]:not(.tapp_flowchart_node--leaf) .tapp_flowchart_node_rect { fill: color-mix(in srgb, var(--tapp_brand-primary) 24%, transparent); }
.tapp_flowchart_node[data-depth="4"]:not(.tapp_flowchart_node--leaf) .tapp_flowchart_node_rect { fill: color-mix(in srgb, var(--tapp_brand-primary) 32%, transparent); }
.tapp_flowchart_node[data-depth="5"]:not(.tapp_flowchart_node--leaf) .tapp_flowchart_node_rect { fill: color-mix(in srgb, var(--tapp_brand-primary) 40%, transparent); }
.tapp_flowchart_node[data-depth="6"]:not(.tapp_flowchart_node--leaf) .tapp_flowchart_node_rect { fill: color-mix(in srgb, var(--tapp_brand-primary) 48%, transparent); }
.tapp_flowchart_node[data-depth="7"]:not(.tapp_flowchart_node--leaf) .tapp_flowchart_node_rect { fill: color-mix(in srgb, var(--tapp_brand-primary) 56%, transparent); }

/* Leaves — full brand fill + inverted text. Same color contract as the
   table's leaf rows so chart + table read as one design language. */
.tapp_flowchart_node--leaf .tapp_flowchart_node_rect {
    fill:   var(--tapp_brand-primary);
    stroke: var(--tapp_brand-primary);
}
.tapp_flowchart_node--leaf .tapp_flowchart_node_label {
    fill: var(--tapp_theme-text-inverted);
}

/* Sunburst arc base — filled, thin separator strokes between rings. */
.tapp_flowchart_nodes path[data-branch] {
    stroke: var(--tapp_theme-background);
    stroke-width: 1.5;
    transition: opacity 160ms;
    cursor: pointer;
}

/* Categorical fills — keyed by top-level branch index (mod 8). */
.tapp_flowchart_nodes path[data-branch="0"] { fill: var(--tapp_chart-cat-1); }
.tapp_flowchart_nodes path[data-branch="1"] { fill: var(--tapp_chart-cat-2); }
.tapp_flowchart_nodes path[data-branch="2"] { fill: var(--tapp_chart-cat-3); }
.tapp_flowchart_nodes path[data-branch="3"] { fill: var(--tapp_chart-cat-4); }
.tapp_flowchart_nodes path[data-branch="4"] { fill: var(--tapp_chart-cat-5); }
.tapp_flowchart_nodes path[data-branch="5"] { fill: var(--tapp_chart-cat-6); }
.tapp_flowchart_nodes path[data-branch="6"] { fill: var(--tapp_chart-cat-7); }
.tapp_flowchart_nodes path[data-branch="7"] { fill: var(--tapp_chart-cat-8); }

/* Hover state — when an arc is hovered the renderer marks the ancestor
   chain with data-on-path and everything else with data-faded. The
   non-path arcs go gray (full desaturation + reduced opacity) so the
   colored path is the only thing that reads, mirroring the sequences-
   sunburst reference. */
.tapp_flowchart_nodes path[data-faded="true"] {
    fill: var(--tapp_theme-text-muted);
    opacity: 0.30;
    transition: fill 120ms, opacity 120ms;
}
.tapp_flowchart_nodes path[data-on-path="true"] {
    opacity: 1;
}

/* Boundary ring — a hairline circle at the chart's outer extent that
   frames the sunburst even when shallow branches don't reach the edge. */
.tapp_flowchart_boundary {
    stroke: var(--tapp_theme-border);
    stroke-width: 1;
    opacity: 0.55;
    pointer-events: none;
}

/* Center readout — visible only on hover. Big percentage sits over a
   smaller node-name caption inside the donut hole. */
.tapp_flowchart_center_value {
    font-family: ui-sans-serif, system-ui, sans-serif;
    font-size: 26px;
    font-weight: 700;
    fill: var(--tapp_theme-text);
    dominant-baseline: middle;
}
.tapp_flowchart_center_label {
    font-family: ui-sans-serif, system-ui, sans-serif;
    font-size: 11px;
    font-weight: 500;
    fill: var(--tapp_theme-text-muted);
    dominant-baseline: middle;
}

/* ─── Hover breadcrumb ─────────────────────────────────────────────────
   Renderer writes one .tapp_chart_breadcrumb_item per ancestor (with
   data-branch="N" so each pill picks up the matching categorical color).
   At rest the host element is empty; on hover it fills left→right with
   the path from root to the focused arc.                              */
.tapp_chart_breadcrumb {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    min-height: 28px;
    padding: 4px 12px;
    margin: 8px 16px 0;
    font-family: ui-sans-serif, system-ui, sans-serif;
    font-size: 12px;
    font-weight: 500;
    color: var(--tapp_theme-text-muted);
}
.tapp_chart_breadcrumb:empty::before {
    content: '';
    display: inline-block;
    height: 20px;   /* keeps the row height stable so the chart doesn't jump */
}
.tapp_chart_breadcrumb_item {
    position: relative;
    display: inline-flex;
    align-items: center;
    padding: 3px 14px 3px 12px;
    border-radius: 3px;
    color: #ffffff;
    background: var(--tapp_chart-cat-1);
    /* Chevron tail: a notched right edge using clip-path so each pill
       points at the next one. The first item has no inset on the left. */
    clip-path: polygon(
        0 0, calc(100% - 8px) 0, 100% 50%,
        calc(100% - 8px) 100%, 0 100%, 8px 50%);
}
.tapp_chart_breadcrumb_item:first-child {
    clip-path: polygon(
        0 0, calc(100% - 8px) 0, 100% 50%,
        calc(100% - 8px) 100%, 0 100%);
    padding-left: 10px;
}
.tapp_chart_breadcrumb_pct {
    margin-left: 6px;
    font-weight: 700;
    color: var(--tapp_theme-text);
}
.tapp_chart_breadcrumb_item[data-branch="0"] { background: var(--tapp_chart-cat-1); }
.tapp_chart_breadcrumb_item[data-branch="1"] { background: var(--tapp_chart-cat-2); }
.tapp_chart_breadcrumb_item[data-branch="2"] { background: var(--tapp_chart-cat-3); }
.tapp_chart_breadcrumb_item[data-branch="3"] { background: var(--tapp_chart-cat-4); }
.tapp_chart_breadcrumb_item[data-branch="4"] { background: var(--tapp_chart-cat-5); }
.tapp_chart_breadcrumb_item[data-branch="5"] { background: var(--tapp_chart-cat-6); }
.tapp_chart_breadcrumb_item[data-branch="6"] { background: var(--tapp_chart-cat-7); }
.tapp_chart_breadcrumb_item[data-branch="7"] { background: var(--tapp_chart-cat-8); }

/* ====================================================================
   iOS-style slider for `.tapp_toggle` checkboxes (framework primitive
   — see doc/DEVELOPER_GUIDE.md → "Framework UI primitives"). Used by
   tcli/epi's override-edit dialog @active control today; available to
   any module that wants a slider-styled toggle.
   Other layouts keep the native checkbox — only Drop repaints to a
   slider. The native input stays the source of truth (keyboard, a11y,
   form data); CSS `appearance: none` removes the native paint and
   ::before/::after draw the track + thumb on the input directly, so no
   wrapping markup is needed.
   ==================================================================== */
input[type="checkbox"].tapp_toggle {
    /* Strip the native checkbox look and turn the box into the pill. */
    appearance:          none;
    -webkit-appearance:  none;
    position:            relative;
    width:               40px;
    height:              22px;
    border-radius:       11px;
    background:          #b0b0b0;
    cursor:              pointer;
    transition:          background 0.18s ease;
    vertical-align:      middle;
    margin:              0;
    flex:                none;
}
input[type="checkbox"].tapp_toggle::before {
    /* Thumb (the dot) — slides right when :checked. */
    content:             "";
    position:            absolute;
    top:                 2px;
    left:                2px;
    width:               18px;
    height:              18px;
    border-radius:       50%;
    background:          #fff;
    box-shadow:          0 1px 3px rgba(0, 0, 0, 0.35);
    transition:          left 0.18s ease;
}
input[type="checkbox"].tapp_toggle:checked {
    background:          var(--tapp_color-success, #27ae60);
}
input[type="checkbox"].tapp_toggle:checked::before {
    left:                20px;
}
input[type="checkbox"].tapp_toggle:focus-visible {
    outline:             2px solid var(--tapp_color-accent, #2980b9);
    outline-offset:      2px;
}
input[type="checkbox"].tapp_toggle:disabled {
    opacity:             0.45;
    cursor:              not-allowed;
}

/* ====================================================================
   3epi year-selector — chevron strip below the flowchart pane.
   Layout (flex row, centered, pinned to bottom) lives in tcli.css;
   Drop paints the panel: subtle elevated surface, brand-tinted
   chevron buttons that gain a soft circular hover, dimmed disabled
   state at the horizon edges.
   ==================================================================== */
#tcli_epi_year_selector {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5em;
    padding: 6px 8px;
    background: var(--tapp_theme-surface-alt);
    border-top: 1px solid var(--tapp_theme-border);
    color: var(--tapp_theme-text);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.02em;
}
#tcli_epi_year_selector button[data-direction] {
    width: 28px;
    height: 28px;
    line-height: 1;
    border: 0;
    background: transparent;
    cursor: pointer;
    border-radius: 50%;
    color: var(--tapp_brand);
    font-size: 16px;
    font-weight: 700;
    transition: background-color 0.15s ease;
}
#tcli_epi_year_selector button[data-direction]:not(:disabled):hover {
    background: color-mix(in oklab, var(--tapp_brand) 12%, transparent);
}
#tcli_epi_year_selector button[data-direction]:disabled {
    color: var(--tapp_theme-text-muted, var(--tapp_theme-text));
    opacity: 0.35;
    cursor: default;
}
#tcli_epi_year_selector > span {
    min-width: 6em;
    text-align: center;
    color: var(--tapp_theme-text);
    font-variant-numeric: tabular-nums;
}

/* ====================================================================
   3epi multi-year table — per-year column pairs with a soft divider
   between years (so the eye can tell Y1 from Y2 quickly), and a
   slightly stronger divider before the Σ summary column. The level-N
   header row sits above its (N | N eligibles) sub-headers via rowspan;
   the colspan'd year header is centered.
   Header backgrounds inherit the inverted band defined above on
   `.tapp_table thead th` — only the body Σ column gets its own
   subtle brand tint so the summary column stands out from the per-year
   pairs.
   ==================================================================== */
.tapp_table[data-multiyear] [data-col="year"] {
    text-align: center;
    border-left: 1px solid color-mix(in oklab, var(--tapp_theme-text-inverted) 30%, transparent);
}
.tapp_table[data-multiyear] [data-col="year"]:first-of-type {
    /* The leftmost year sits next to Rate; no extra divider needed. */
    border-left: none;
}
.tapp_table[data-multiyear] thead [data-col="sum"] {
    border-left: 2px solid color-mix(in oklab, var(--tapp_theme-text-inverted) 50%, transparent);
    /* Enlarge the Σ glyph in the header — visually the column's anchor.
       Drops the uppercase letter-spacing from the standard header rules
       so the symbol isn't tracked apart. */
    font-size: 22px;
    text-transform: none;
    letter-spacing: 0;
    line-height: 1;
}
.tapp_table[data-multiyear] tbody td[data-col="sum"] {
    font-weight: 700;
}
/* The Σ cell in the total rows sits on the inverted band; the divider
   from the per-year pairs uses a translucent inverted-text stroke so
   it stays visible against the dark band. */
.tapp_table[data-multiyear] tr[data-total] [data-col="sum"] {
    border-left: 2px solid color-mix(in oklab, var(--tapp_theme-text-inverted) 50%, transparent);
}

/* ====================================================================
   Pref toggles (animations, sound) — render as icon-button toggles,
   exactly like the theme switch above. The wrapping <label class=
   "tapp_switch tapp_pref_switch"> picks up Drop's existing
   .tapp_switch sizing/hover/cursor; the `display: none` rules above
   on `.tapp_switch input, .tapp_switch_slider` already hide the
   native control and slider. The `.tapp_label` next to it is also
   hidden by the global rule (~line 234), so visually only the icon
   remains. Per-pref icon comes from a `data-pref` attribute on the
   label.

   Stroke colors mirror the theme-switch pattern: dark (#444) in
   light mode, light (#e0e4ea) in dark mode. Two rules per pref
   (light + dark) is the unavoidable cost of using data: URLs.
   ==================================================================== */
#tapp_header .tapp_pref_switch {
    /* Sizing/hover/cursor inherits from #tapp_header .tapp_switch
       (~line 295). This rule just supplies the background-image
       slot for the per-pref icon and the positioning context for
       the off-state prohibit overlay below. */
    position: relative;
    background-repeat: no-repeat;
    background-position: center;
    background-size: 16px 16px;
}
/* Light-mode default — dark stroke on Drop's light header. */
#tapp_header .tapp_pref_switch[data-pref="animations"] {
    /* Film strip (Lucide 'Film' glyph) — universal motion icon. */
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444444' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect width='18' height='18' x='3' y='3' rx='2'/><path d='M7 3v18'/><path d='M3 7.5h4'/><path d='M3 12h18'/><path d='M3 16.5h4'/><path d='M17 3v18'/><path d='M17 7.5h4'/><path d='M17 16.5h4'/></svg>");
}
#tapp_header .tapp_pref_switch[data-pref="sound"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23444444' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polygon points='11 5 6 9 2 9 2 15 6 15 11 19 11 5'/><path d='M15.5 8.5a5 5 0 0 1 0 7'/><path d='M19 5a9 9 0 0 1 0 14'/></svg>");
}
/* Dark-mode override — light stroke for legibility on Drop's dark
   header. Same convention as the theme switch + language select. */
:root[tapp-theme="dark"] #tapp_header .tapp_pref_switch[data-pref="animations"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23e0e4ea' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect width='18' height='18' x='3' y='3' rx='2'/><path d='M7 3v18'/><path d='M3 7.5h4'/><path d='M3 12h18'/><path d='M3 16.5h4'/><path d='M17 3v18'/><path d='M17 7.5h4'/><path d='M17 16.5h4'/></svg>");
}
:root[tapp-theme="dark"] #tapp_header .tapp_pref_switch[data-pref="sound"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23e0e4ea' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polygon points='11 5 6 9 2 9 2 15 6 15 11 19 11 5'/><path d='M15.5 8.5a5 5 0 0 1 0 7'/><path d='M19 5a9 9 0 0 1 0 14'/></svg>");
}

/* Off-state decoration — universal "prohibited" sign over the icon
   when the inner checkbox is NOT checked. Modern :has() (Chromium,
   Safari 15.4+, Firefox 121+) lets the wrapping label react to the
   child input's state without any JS state-mirroring. Circle
   (::before) + diagonal stroke (::after), both currentColor so they
   adapt to theme/dark mode for free. */
#tapp_header .tapp_pref_switch:has(input:not(:checked)) {
    opacity: 0.75;
}
#tapp_header .tapp_pref_switch:has(input:not(:checked))::before,
#tapp_header .tapp_pref_switch:has(input:not(:checked))::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    pointer-events: none;
    z-index: 1;
}
#tapp_header .tapp_pref_switch:has(input:not(:checked))::before {
    width: 20px;
    height: 20px;
    margin-top: -10px;
    margin-left: -10px;
    border: 2px solid currentColor;
    border-radius: 50%;
    box-sizing: border-box;
}
#tapp_header .tapp_pref_switch:has(input:not(:checked))::after {
    width: 22px;
    height: 2px;
    margin-top: -1px;
    margin-left: -11px;
    background: currentColor;
    transform: rotate(-45deg);
    transform-origin: center;
}


/* ============================================
   Empty-state pattern — cross-module.
   Any module's "noFile / noData / validationError" branch wraps
   its content in <div data-empty-state>; Drop centers everything
   in a column with the brand-logo image up top, sized to feel
   like a focal point rather than an inline detail. The first
   adopter is 3pro (r372+); tmec-cpr / tcli-epi should pick up
   the same hook in a follow-up so empty states feel coherent
   across modules.

   Markup contract:
     <div data-empty-state [hidden]>
       <img class="tapp_empty_state_logo" src="…">  (3app default
                                                     or HESL's own
                                                     <teff:app id="tapp">
                                                     /<teff:gen>/<teff:logo>)
       <p>…copy paragraphs…</p>
       <ul></ul>   (optional — used by validationError)
     </div>
   ============================================ */
/* :not([hidden]) — author-rule display: flex would otherwise win the
   specificity tie with the browser default for [hidden] (both 0,1,0
   — author wins), painting three stacked branches all at once. */
[data-empty-state]:not([hidden]) {
    display:         flex;
    flex-direction:  column;
    align-items:     center;
    justify-content: center;
    text-align:      center;
    gap:             14px;
    /* Vertical breathing room so the empty state reads as a
       deliberate "here's what to do" panel rather than as a
       leftover stub. */
    padding:         48px 32px;
    min-height:      280px;
    color:           color-mix(in oklab, var(--tapp_theme-text) 75%, transparent);
}
[data-empty-state] > .tapp_empty_state_logo {
    width:      200px;
    height:     200px;
    object-fit: contain;
    opacity:    0.92;
}
[data-empty-state] > p {
    max-width:  520px;
    margin:     0;
    font-size:  14px;
    line-height: 1.5;
}
[data-empty-state] > ul {
    max-width: 520px;
    margin:    0;
    padding-left: 20px;
    text-align: left;
    font-size: 13px;
    color: color-mix(in oklab, var(--tapp_theme-text) 70%, transparent);
}

/* ============================================
   3PRO presentation stage — fills the feature section height.
   tpro uses a single TApp.createSection body card (.tapp_section).
   Forcing the feature section to a 1fr row makes that card stretch
   to the available viewport height. overflow:hidden replaces the
   default overflow:auto so no scroll bar appears around the stage.

   Specificity: (2,1,1) beats the Drop default (1,1,1) on overflow;
   grid-template-rows is unset in Drop's feature-section rule, so
   any specificity wins.

   The iframe slot is positioned absolute within the body card
   (position:relative from Drop's body-card rule). Insets match
   Drop's body-card padding: top 60 px (toolbar pill), sides 24 px,
   bottom 20 px. */
#tapp_workspace > section.tapp_feature_section:has(#tpro_pres_workspace) {
    grid-template-rows: 1fr;
    overflow: hidden;
}

[data-tpro-iframe-slot] {
    position: absolute;
    top:    60px;
    left:   24px;
    right:  24px;
    bottom: 20px;
}

[data-tpro-stage] {
    display: block;
    width:   100%;
    height:  100%;
    border:  none;
}

/* ====================================================================
   tval / framework primitives — paint layer (Drop)
   Column-header filter, condensed tables, stale-price warnings, detail
   meta, chart period chips, valuetimeseries. Structural rules (float,
   alignment) live in base.css; this is surface paint only.
   ==================================================================== */

/* ===== Column-header filter (TApp.columnFilter) — v0.3-style =====
   A plain ▼ toggle inline with the header label; the dropdown is appended to
   <body> and positioned by JS, so its CSS is context-free. */
.tapp_colfilter_toggle {
    margin-left: 6px;
    padding: 2px;
    border: none;
    background: none;
    color: inherit;            /* white on the dark thead */
    opacity: 0.6;
    font-size: 0.7em;
    line-height: 1;
    vertical-align: middle;
    cursor: pointer;
    transition: opacity 120ms, color 120ms;
}
.tapp_colfilter_toggle:hover { opacity: 1; }
/* Active filter — an accent pill carrying the count ("▼ 2"), so the column
   clearly reads "filter on" and how many values are applied. */
.tapp_colfilter_toggle[data-active] {
    opacity: 1;
    color: #fff;
    background: var(--tapp_brand-accent-a, #4ea1ff);
    border-radius: 8px;
    padding: 1px 6px;
    font-size: 0.62em;
    font-weight: 600;
}

/* Dropdown card (body-level). */
.tapp_colfilter_panel {
    z-index: 99000;
    min-width: 200px;
    max-width: 320px;
    background: var(--tapp_theme-surface);
    color: var(--tapp_theme-text);
    border: 1px solid var(--tapp_theme-border);
    border-radius: 8px;
    box-shadow: 0 6px 24px var(--tapp_theme-shadow);
    padding: 10px;
    font-weight: normal;
}
.tapp_colfilter_title {
    font-weight: 600; font-size: 11px; text-transform: uppercase; letter-spacing: 0.03em;
    opacity: 0.6; margin-bottom: 8px;
}
.tapp_colfilter_options { display: flex; flex-direction: column; gap: 2px; max-height: 220px; overflow-y: auto; margin-bottom: 10px; }
.tapp_colfilter_option { display: flex; align-items: center; gap: 8px; font-size: 13px; padding: 3px 4px; border-radius: 4px; cursor: pointer; white-space: nowrap; }
.tapp_colfilter_option:hover { background: var(--tapp_theme-surface-alt, rgba(0,0,0,0.04)); }
.tapp_colfilter_empty { font-size: 12px; opacity: 0.6; padding: 6px 4px; }
.tapp_colfilter_range { display: flex; flex-direction: column; gap: 6px; margin-bottom: 10px; }
.tapp_colfilter_range label { display: flex; align-items: center; gap: 6px; font-size: 13px; }
.tapp_colfilter_input { flex: 1; padding: 4px 6px; box-sizing: border-box; border: 1px solid var(--tapp_theme-border); border-radius: 4px; background: var(--tapp_theme-surface); color: var(--tapp_theme-text); }
.tapp_colfilter_actions { display: flex; gap: 6px; }
.tapp_colfilter_compare { display: flex; gap: 6px; align-items: center; margin-bottom: 10px; }
.tapp_colfilter_op {
    flex: 0 0 auto; padding: 4px 6px; border: 1px solid var(--tapp_theme-border); border-radius: 4px;
    background: var(--tapp_theme-surface); color: var(--tapp_theme-text); font-size: 14px;
}
.tapp_colfilter_compare .tapp_colfilter_input { flex: 1 1 auto; }
.tapp_colfilter_apply, .tapp_colfilter_clear {
    flex: 1; padding: 5px 8px; border-radius: 5px; cursor: pointer; font-size: 12px; font-weight: 500;
    border: 1px solid var(--tapp_theme-border);
}
.tapp_colfilter_apply { background: var(--tapp_brand-primary); color: var(--tapp_theme-text-inverted); border-color: var(--tapp_brand-primary); }
.tapp_colfilter_clear { background: transparent; color: var(--tapp_theme-text); }
.tapp_colfilter_clear:hover { background: var(--tapp_theme-surface-alt, rgba(0,0,0,0.04)); }
.tapp_colfilter_loading { display: flex; justify-content: center; padding: 18px; }
.tapp_colfilter_spinner {
    width: 22px; height: 22px;
    border: 2px solid var(--tapp_theme-border);
    border-top-color: var(--tapp_brand-primary);
    border-radius: 50%;
    animation: tapp_colfilter_spin 0.8s linear infinite;
}
@keyframes tapp_colfilter_spin { to { transform: rotate(360deg); } }

/* Condensed table — tighter rows. Double-class selector so it out-specifies
   `.tapp_table thead th` (0,1,2), which otherwise wins on the header cells. */
.tapp_table.tapp_table-condensed thead th,
.tapp_table.tapp_table-condensed td {
    padding-top: 2px;
    padding-bottom: 2px;
    font-size: 12px;
}

/* Stale-price warning row + date text. Shade the CELLS, and out-specify
   `.tapp_table tbody td` (0,1,2) which sets the surface bg — otherwise the
   tint only shows on hover. */
.tapp_table tbody tr.tapp_row-warn > td { background-color: rgba(220, 38, 38, 0.14); }
.tapp_table tbody tr.tapp_row-warn:hover > td { background-color: rgba(220, 38, 38, 0.22); }
.tapp_text-warn { color: #dc2626; font-weight: 600; }

/* Detail meta row + fields. */
.tapp_detail_meta { display: flex; flex-wrap: wrap; gap: 16px; margin: 8px 0; font-size: 13px; }
.tapp_detail_field { color: var(--tapp_theme-text); }

/* Chart period chips + active button state. */
.tapp_chart_periods { display: flex; justify-content: center; gap: 4px; margin: 8px 0; }
.tapp_chart_period { padding: 2px 10px; font-size: 12px; }
.tapp_btn-active {
    background: var(--tapp_brand-primary);
    color: var(--tapp_theme-text-inverted);
    border-color: var(--tapp_brand-primary);
}

/* valuetimeseries — axes/grid/labels paint (series colors stay inline). */
.tapp_valuetimeseries_tick { fill: var(--tapp_theme-text); opacity: 0.7; }
.tapp_valuetimeseries_grid { stroke: var(--tapp_theme-border); }
.tapp_valuetimeseries_axis { stroke: var(--tapp_theme-text); opacity: 0.4; }
.tapp_valuetimeseries_pctlabel--up { fill: #16a34a; }
.tapp_valuetimeseries_pctlabel--down { fill: #dc2626; }
.tapp_valuetimeseries_legend_label { font-size: 11px; fill: var(--tapp_theme-text); }

/* Panel (TApp.panel) — surface + header paint (positioning is below).
   .tapp_panel_close reuses the pre-existing close-× primitive. */
.tapp_panel_surface {
    background: var(--tapp_theme-surface);
    border: 1px solid var(--tapp_theme-border);
    box-shadow: 0 8px 32px var(--tapp_theme-shadow);
    padding: 16px;
}
.tapp_panel[data-modal="true"] .tapp_panel_surface { border-radius: 12px; }
/* Modal backdrop — dim + blur the whole app behind the panel so the panel
   is the only thing in focus while it blocks interaction. */
.tapp_panel[data-modal="true"] .tapp_panel_backdrop {
    background: rgba(0, 0, 0, 0.25);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}
.tapp_panel_header {
    margin-bottom: 12px;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--tapp_theme-border);
}
.tapp_panel_title { margin: 0; font-size: 15px; }
/* Dimmed subtitle beside the panel title (e.g. selection count); the close
   button is pushed to the far right so title + subtitle stay grouped left. */
.tapp_panel_subtitle { font-size: 12px; opacity: 0.55; white-space: nowrap; }
.tapp_panel_header > .tapp_panel_close { margin-left: auto; }

/* ── Structural positioning for the panel primitive.
   (base.css is tokens-only, so the overlay geometry lives here.) ───────── */

/* Numeric table cells — right-aligned, tabular figures. */
.tapp_num { text-align: right; font-variant-numeric: tabular-nums; }

/* valuetimeseries text sizing. */
.tapp_valuetimeseries text { font-size: 11px; }
.tapp_valuetimeseries_pctlabel { font-size: 10px; }

/* Panel — fixed, top-of-everything overlay (mounts at <body>). Hidden when
   closed. MODAL covers + blocks the whole viewport; MODELESS docks to a
   viewport edge and leaves the rest of the app interactive. */
.tapp_panel { position: fixed; z-index: 99500; }
.tapp_panel[hidden] { display: none; }
.tapp_panel_header { display: flex; align-items: center; justify-content: space-between; gap: 12px; }

/* Modal — full-viewport overlay; surface docked by placement (auto margins).
   :not([hidden]) so the overlay display never defeats the closed state. */
.tapp_panel[data-modal="true"]:not([hidden]) { inset: 0; display: flex; }
.tapp_panel[data-modal="true"] .tapp_panel_backdrop { position: absolute; inset: 0; }
.tapp_panel[data-modal="true"] .tapp_panel_surface { position: relative; margin: auto; max-height: 100%; max-width: 100%; overflow: auto; }
.tapp_panel[data-modal="true"][data-placement="center"] .tapp_panel_surface { width: min(960px, 92vw); max-height: 90vh; }
.tapp_panel[data-modal="true"][data-placement="up"]    .tapp_panel_surface { margin: 0 auto auto; width: 100%; }
.tapp_panel[data-modal="true"][data-placement="down"]  .tapp_panel_surface { margin: auto auto 0;  width: 100%; }
.tapp_panel[data-modal="true"][data-placement="left"]  .tapp_panel_surface { margin: 0 auto 0 0;   height: 100%; }
.tapp_panel[data-modal="true"][data-placement="right"] .tapp_panel_surface { margin: 0 0 0 auto;   height: 100%; }

/* Modeless — docked to a viewport edge; root only spans the dock area so the
   app stays clickable. Surface caps its size and scrolls. */
.tapp_panel[data-modal="false"][data-placement="down"]   { left: 0; right: 0; bottom: 0; }
.tapp_panel[data-modal="false"][data-placement="up"]     { left: 0; right: 0; top: 0; }
.tapp_panel[data-modal="false"][data-placement="left"]   { left: 0; top: 0; bottom: 0; max-width: 92vw; }
.tapp_panel[data-modal="false"][data-placement="right"]  { right: 0; top: 0; bottom: 0; max-width: 92vw; }
.tapp_panel[data-modal="false"][data-placement="center"] { left: 50%; top: 50%; transform: translate(-50%, -50%); max-width: 92vw; }
.tapp_panel[data-modal="false"] .tapp_panel_surface { max-height: 48vh; overflow: auto; }
.tapp_panel[data-modal="false"][data-placement="down"] .tapp_panel_surface { border-radius: 12px 12px 0 0; }
.tapp_panel[data-modal="false"][data-placement="up"]   .tapp_panel_surface { border-radius: 0 0 12px 12px; }
.tapp_panel[data-modal="false"][data-placement="left"]  .tapp_panel_surface,
.tapp_panel[data-modal="false"][data-placement="right"] .tapp_panel_surface { width: min(560px, 92vw); max-height: 100vh; height: 100%; }
.tapp_panel[data-modal="false"][data-placement="left"]  .tapp_panel_surface { border-radius: 0 12px 12px 0; }
.tapp_panel[data-modal="false"][data-placement="right"] .tapp_panel_surface { border-radius: 12px 0 0 12px; }

/* ════════════════════════════════════════════════════════════════════════
   Scrollable table card (.tapp_table_wrap).
   Contains a .tapp_table; sibling .tapp_pagination stays outside and is
   always visible above the bottom panel overlay (which is max-height:48vh).
   The 50vh cap leaves the pager in the top half of the viewport at all times.
   ════════════════════════════════════════════════════════════════════════ */
.tapp_table_wrap {
    overflow-y: auto;
    max-height: calc(50vh - 2rem);
    border-bottom: 1px solid var(--tapp_theme-border);
}
/* Larger screens can show more rows — lift the cap to 65vh. */
@media (min-height: 800px) {
    .tapp_table_wrap { max-height: calc(65vh - 2rem); }
}

/* Row selection (3val comparison) — the checkbox is a visual indicator;
   the ROW click drives toggle/shift-range, so the box ignores pointer. */
.tapp_sel { width: 1%; white-space: nowrap; text-align: center; }
.tapp_sel_cb { cursor: pointer; }
/* Selection tint on the CELLS; same specificity bump as the warn rule, and
   placed after it so a selected+stale row reads as selected. */
.tapp_table tbody tr.tapp_row-selected > td { background-color: color-mix(in srgb, var(--tapp_brand-primary) 18%, transparent); }

/* Toolbar glyphs (data-icon background-image; base rule zeroes the text).
   SVG paths match the Lucide icons used in r169 toolbar templates. */
.tapp_toolbar_button[data-icon="compare"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='18' cy='18' r='3'/><circle cx='6' cy='6' r='3'/><path d='M13 6h3a2 2 0 0 1 2 2v7'/><path d='M11 18H8a2 2 0 0 1-2-2V9'/></svg>");
}
.tapp_toolbar_button[data-icon="condense"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M3 6h18'/><path d='M3 12h18'/><path d='M3 18h18'/></svg>");
}
.tapp_toolbar_button[data-icon="clear-selection"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='10'/><path d='m15 9-6 6'/><path d='m9 9 6 6'/></svg>");
}
.tapp_toolbar_button[data-icon="reset"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M3 12a9 9 0 1 0 3-6.7L3 8'/><path d='M3 3v5h5'/></svg>");
}
.tapp_toolbar_button[data-icon="link-org"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71'/><path d='M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71'/></svg>");
}
.tapp_toolbar_button[data-icon="add-license"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z'/><polyline points='14 2 14 8 20 8'/><line x1='12' y1='12' x2='12' y2='17'/><line x1='9.5' y1='14.5' x2='14.5' y2='14.5'/></svg>");
}
.tapp_toolbar_button[data-icon="show-selection"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M10 6H21'/><path d='M10 12H21'/><path d='M10 18H21'/><polyline points='3 6 4 7 6 5'/><polyline points='3 12 4 13 6 11'/><polyline points='3 18 4 19 6 17'/></svg>");
}
.tapp_toolbar_button[data-icon="save-selection"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='m19 21-7-4-7 4V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16z'/><line x1='12' y1='7' x2='12' y2='13'/><line x1='9' y1='10' x2='15' y2='10'/></svg>");
}
.tapp_toolbar_button[data-icon="load-selection"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='m19 21-7-4-7 4V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v16z'/><path d='m9 10 2 2 4-4'/></svg>");
}
.tapp_toolbar_button[data-icon="download"] {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23222' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4'/><polyline points='7 10 12 15 17 10'/><line x1='12' y1='15' x2='12' y2='3'/></svg>");
}
/* Toggled-on toolbar button (e.g. condensed view active). */
.tapp_toolbar > .tapp_toolbar_button-active {
    background-color: color-mix(in oklab, var(--tapp_brand-primary) 22%, transparent);
}

/* ════════════════════════════════════════════════════════════════════════
   Dialog tab nav (TApp.dialog.modal with opts.tabs).
   Flat divs — not nav>ul — so the dialog action button CSS doesn't apply.
   ════════════════════════════════════════════════════════════════════════ */
.tapp_dialog_tabs {
    display:       flex;
    gap:           2px;
    border-bottom: 1px solid var(--tapp_theme-border);
    margin-bottom: 12px;
}
.tapp_dialog_tab_btn {
    padding:       6px 14px;
    background:    transparent;
    border:        1px solid transparent;
    border-bottom: 2px solid transparent;
    border-radius: 4px 4px 0 0;
    cursor:        pointer;
    font:          inherit;
    font-size:     0.9em;
    color:         var(--tapp_theme-text-muted);
    transition:    color 120ms, border-color 120ms;
}
.tapp_dialog_tab_btn:hover:not([data-active]) {
    background: var(--tapp_theme-surface-alt);
    color:      var(--tapp_theme-text);
}
.tapp_dialog_tab_btn[data-active] {
    border-bottom-color: var(--tapp_brand-primary);
    color:               var(--tapp_brand-primary);
    font-weight:         600;
}
.tapp_dialog_tab_panel {
    min-height: 120px;
}

/* ════════════════════════════════════════════════════════════════════════
   File-settings Pricing tab
   ════════════════════════════════════════════════════════════════════════ */
.tapp_pricing_tab {
    display:   flex;
    flex-direction: column;
    gap:       10px;
    max-height: 58vh;
    overflow-y: auto;
}
/* Toolbar row: Fetch + Reset, right-aligned */
.tapp_pricing_toolbar {
    display:    flex;
    align-self: flex-end;
    gap:        .5rem;
}
/* Apply button (confirm footer) */
.tapp_pricing_apply_btn {
    padding:       6px 14px;
    background:    var(--tapp_brand-secondary);
    color:         var(--tapp_theme-text-inverted);
    border:        1px solid var(--tapp_brand-secondary);
    border-radius: 9999px;
    cursor:        pointer;
    font:          inherit;
    transition:    background-color 120ms;
}
.tapp_pricing_apply_btn:hover:not(:disabled) {
    background: var(--tapp_theme-link-hover);
    border-color: var(--tapp_theme-link-hover);
}
.tapp_pricing_apply_btn:disabled { opacity: 0.4; cursor: default; }
.tapp_pricing_unchanged td  { opacity: 0.45; }
.tapp_pricing_unchanged input[type="checkbox"] { cursor: default; }
.tapp_confirm_footer {
    display:        flex;
    gap:            8px;
    justify-content: flex-end;
    align-items:    center;
    padding-top:    8px;
    border-top:     1px solid var(--tapp_theme-border);
    margin-top:     4px;
}

/* ════════════════════════════════════════════════════════════════════════
   Autocomplete dropdown (used in dialog table-row inputs).
   Containing <td> must have position:relative.
   ════════════════════════════════════════════════════════════════════════ */
.tapp_autocomplete_drop {
    position:         absolute;
    z-index:          9999;
    left:             0;
    top:              calc(100% + 2px);
    width:            100%;
    max-height:       180px;
    overflow-y:       auto;
    background:       var(--tapp_theme-surface);
    border:           1px solid var(--tapp_theme-border);
    border-radius:    4px;
    box-shadow:       0 4px 12px rgba(0,0,0,.12);
    display:          none;
}
.tapp_autocomplete_drop_item {
    display:          flex;
    justify-content:  space-between;
    align-items:      center;
    padding:          0.35rem 0.75rem;
    cursor:           pointer;
    font-size:        0.875rem;
    gap:              0.5rem;
}
.tapp_autocomplete_drop_item:hover {
    background: var(--tapp_theme-surface-alt, rgba(0,0,0,.06));
}
.tapp_autocomplete_drop_item_primary {
    flex:             1;
    min-width:        0;
    overflow:         hidden;
    text-overflow:    ellipsis;
    white-space:      nowrap;
}
.tapp_autocomplete_drop_item_secondary {
    flex-shrink:      0;
    font-size:        0.8125rem;
    color:            var(--tapp_theme-text-muted, #9ca3af);
}
.tapp_autocomplete_drop_empty {
    padding:          0.4rem 0.75rem;
    font-size:        0.8125rem;
    color:            var(--tapp_theme-text-muted, #9ca3af);
}
@media (prefers-color-scheme: dark) {
    .tapp_autocomplete_drop { box-shadow: 0 4px 12px rgba(0,0,0,.4); }
}
:root[data-theme="dark"]  .tapp_autocomplete_drop { box-shadow: 0 4px 12px rgba(0,0,0,.4); }
:root[data-theme="light"] .tapp_autocomplete_drop { box-shadow: 0 4px 12px rgba(0,0,0,.12); }

/* ── Help & Support dialog ─────────────────────────────────────────────── */
.tapp_help_dialog {
    display:    flex;
    flex-direction: row;
    gap:        0;
    min-height: min(420px, 70vh);
}
.tapp_help_nav {
    display:        flex;
    flex-direction: column;
    gap:            2px;
    width:          172px;
    flex-shrink:    0;
    padding:        0.25rem 0.5rem 0.25rem 0;
    border-right:   1px solid var(--tapp_theme-border, rgba(0,0,0,.1));
    margin-right:   1.25rem;
}
.tapp_help_nav_btn {
    display:         flex;
    align-items:     center;
    gap:             0.55rem;
    width:           100%;
    text-align:      left;
    padding:         0.5rem 0.7rem;
    border:          none;
    border-radius:   6px;
    background:      transparent;
    color:           var(--tapp_theme-text, #111);
    font-size:       0.875rem;
    cursor:          pointer;
    transition:      background 0.12s, color 0.12s;
}
.tapp_help_nav_btn:hover {
    background: var(--tapp_theme-surface-alt, rgba(0,0,0,.05));
}
.tapp_help_nav_btn[data-active] {
    background:  var(--tapp_brand-primary, #1a56c4);
    color:       #fff;
    font-weight: 600;
}
.tapp_help_nav_icon {
    font-size:   1rem;
    flex-shrink: 0;
    opacity:     0.75;
    line-height: 1;
}
.tapp_help_nav_btn[data-active] .tapp_help_nav_icon {
    opacity: 1;
}
.tapp_help_nav_label {
    flex: 1;
    min-width: 0;
}
.tapp_help_body {
    flex:       1;
    min-width:  0;
    overflow-y: auto;
    padding:    0.125rem 0;
}
.tapp_help_panel {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}
.tapp_help_panel[hidden] { display: none; }
.tapp_help_contact {
    margin: 0;
    font-size: 0.9rem;
}
.tapp_help_contact a {
    color: var(--tapp_brand-primary, #1a56c4);
    text-decoration: none;
}
.tapp_help_contact a:hover {
    text-decoration: underline;
}
.tapp_help_meta {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: 0.25rem 0.75rem;
    margin: 0;
    font-size: 0.875rem;
}
.tapp_help_meta dt {
    color: var(--tapp_theme-text-muted, #6b7280);
    font-weight: 500;
}
.tapp_help_meta dd { margin: 0; }
.tapp_help_lib_list {
    list-style: none;
    margin:     0;
    padding:    0;
    display:    flex;
    flex-direction: column;
    gap: 0.25rem;
}
.tapp_help_lib {
    border:        1px solid var(--tapp_theme-border, rgba(0,0,0,.1));
    border-radius: 6px;
    overflow:      hidden;
}
.tapp_help_lib_header {
    display:         flex;
    align-items:     center;
    gap:             0.5rem;
    padding:         0.5rem 0.75rem;
    cursor:          pointer;
    font-size:       0.875rem;
    list-style:      none;
    background:      var(--tapp_theme-surface, #f9fafb);
    user-select:     none;
}
.tapp_help_lib_header::-webkit-details-marker { display: none; }
.tapp_help_lib_header::marker               { content: ''; }
.tapp_help_lib:not([open]) > .tapp_help_lib_header::before {
    content: '▶️';
    font-size: 0.65rem;
    flex-shrink: 0;
}
.tapp_help_lib[open] > .tapp_help_lib_header::before {
    content: '🔽';
    font-size: 0.65rem;
    flex-shrink: 0;
}
.tapp_help_lib_header:hover {
    background: var(--tapp_theme-surface-alt, rgba(0,0,0,.04));
}
.tapp_help_lib_name {
    font-weight: 600;
    flex: 1;
}
.tapp_help_lib_version {
    font-size:  0.75rem;
    color:      var(--tapp_theme-text-muted, #6b7280);
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
}
.tapp_help_lib_license {
    font-size:       0.7rem;
    font-weight:     600;
    letter-spacing:  0.04em;
    background:      rgba(0,0,0,.06);
    border-radius:   4px;
    padding:         0.15em 0.45em;
    color:           var(--tapp_theme-text-muted, #374151);
    white-space:     nowrap;
}
.tapp_help_lib_text {
    margin:      0;
    padding:     0.75rem;
    font-size:   0.72rem;
    line-height: 1.55;
    white-space: pre-wrap;
    word-break:  break-word;
    color:       var(--tapp_theme-text-muted, #6b7280);
    border-top:  1px solid var(--tapp_theme-border, rgba(0,0,0,.08));
    background:  var(--tapp_theme-surface, #fafafa);
    font-family: inherit;
    max-height:  12rem;
    overflow-y:  auto;
}
:root[tapp-theme="dark"] .tapp_help_lib_license {
    background: rgba(255,255,255,.1);
}
:root[tapp-theme="dark"] .tapp_help_contact a {
    color: var(--tapp_brand-accent-a, #5fa6e3);
}
:root[tapp-theme="dark"] .tapp_help_nav_btn[data-active] {
    color: #fff;
}
.tapp_help_about_product {
    margin:      0 0 0.1rem;
    font-size:   1.4rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    color:       var(--tapp_brand-primary, #1a56c4);
}
.tapp_help_about_tagline {
    margin:    0 0 1rem;
    font-size: 0.85rem;
    color:     var(--tapp_theme-text-muted, #6b7280);
}
.tapp_help_about_copyright {
    margin:      0.75rem 0 0;
    font-size:   0.78rem;
    line-height: 1.55;
    color:       var(--tapp_theme-text-muted, #6b7280);
    border-top:  1px solid var(--tapp_theme-border, rgba(0,0,0,.1));
    padding-top: 0.75rem;
}

