/* Platform-wide tab component. `.global-tabs` / `.global-tab` is the canonical underline
   tab strip for the whole app. Every surface uses these classes directly. */

/* ── Canonical component ── the `.global-tabs` bottom border is the seam where the
   strip meets the content below it. */
.global-tabs {
    display: flex;
    gap: var(--spacing-2xs);
    flex-wrap: wrap;
    border-bottom: 1px solid var(--color-border);
}

/* Standalone strips (not built into a card's bottom edge) want a little air
   between the seam and the panel that follows. */
.global-tabs--spaced {
    margin-bottom: var(--spacing-mdlg);
}

.global-tab {
    border: 0;
    background: none;
    font: inherit;
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    color: var(--color-text-muted);
    text-decoration: none;
    padding: var(--spacing-sm) var(--spacing-md);
    cursor: pointer;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-xsm);
    transition: color 0.15s, border-color 0.15s;
}

.global-tab:hover {
    color: var(--color-text);
}

.global-tab.is-active {
    color: var(--color-action);
    border-bottom-color: var(--color-action);
}

/* --neutral: originally the escape hatch that marked the active tab in neutral
   dark grey instead of the brand accent. The interaction layer made that the
   base look (tabs are quiet controls, so every strip marks active in action
   ink); what the modifier still carries is the tighter tab rhythm — see the
   rhythm rules further down. */

.global-tab:focus-visible {
    outline: 2px solid var(--color-focus-ring);
    outline-offset: 2px;
    border-radius: 4px;
}

.global-tab__icon {
    display: inline-flex;
    align-items: center;
    line-height: 1;
}

/* Trailing "+" add-view tab (HubSpot add-view pattern) — an icon-only tab that opens
   the create flow rather than navigating. No label, no active underline; it reads as an
   action, not a destination. */
.global-tab--add {
    padding-inline: var(--spacing-smd);
}

.global-tab--add .global-tab__icon {
    font-size: var(--font-size-md);
}

/* The "+" tab's two-option menu — organization view vs personal. position:fixed
   for the same reason the opportunities toolbar's menus are (toolbar.css): the
   header strip is a sideways scroller (`overflow-x: auto`, page-header.css), and
   an overflow of auto on one axis clips the other axis too — an absolute menu
   hanging below the strip paints into the nav's scroll box instead of over the
   page. The trigger computes top/left from its own rect when it opens. */
.global-tab-add {
    display: inline-flex;
}

.global-tab-add__menu {
    position: fixed;
    z-index: var(--z-dropdown);
    min-width: 15rem;
    padding: var(--spacing-xsm);
    background: var(--color-card-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-lg);
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2xs);
}

.global-tab-add__option {
    display: flex;
    align-items: flex-start;
    gap: var(--spacing-sm);
    width: 100%;
    padding: var(--spacing-sm) var(--spacing-sm);
    border: 0;
    background: none;
    border-radius: var(--radius-sm);
    font: inherit;
    text-align: left;
    cursor: pointer;
    color: var(--color-text);
}

.global-tab-add__option:hover {
    background: var(--color-surface-hover);
}

/* Nudged down so the glyph centers on the option's first (label) line. */
.global-tab-add__option > i {
    color: var(--color-text-muted);
    margin-top: var(--spacing-2xs);
}

.global-tab-add__label {
    display: block;
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
}

.global-tab-add__hint {
    display: block;
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
}

/* Who-sees-it marker after a tab's label — every tab wears one (Nick, 10-01):
   a person = Just for me, people = Everyone, a person-check = Specific people
   (_saved_view_audience_badge.html). Quiet on purpose: muted, no chip
   background, sized under the label so it reads as a property of the tab
   rather than a count or an action. */
.global-tab__sharing {
    display: inline-flex;
    align-items: center;
    line-height: 1;
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
}

/* ── Hover box ── HubSpot's tab hover treatment, on --neutral strips only (the
   six saved-view strips): a hovered tab gets a soft box, not just the base
   strip's text-color nudge. Top corners round; the bottom stays square so the
   box sits ON the strip's seam instead of floating above it. :focus-within
   keeps the box while the tab (an <a>) holds keyboard focus. */
.global-tabs--neutral .global-tab:hover,
.global-tabs--neutral .global-tab:focus-within {
    background: var(--color-surface-hover);
    border-radius: var(--radius-sm) var(--radius-sm) var(--radius-none) var(--radius-none);
    color: var(--color-text);
}

/* ── Neutral strip rhythm ── the saved-view strips run many tabs in one row, so
   they sit a notch tighter than the base component's 0.9rem. Both rules are
   (0,2,0): the --add one must restate itself here or the strip rule above it
   would beat the base `.global-tab--add` (0,1,0) and the "+" would widen back
   to 0.75rem. */
.global-tabs--neutral .global-tab {
    padding-inline: var(--spacing-smd);
}

.global-tabs--neutral .global-tab--add {
    padding-inline: var(--spacing-sm);
}

/* ── In-strip management ── chrome rides PER-TAB classes, because one strip can
   mix tabs the viewer manages with tabs they don't (a member's personal tab
   beside org tabs; a board manager's board tabs beside admin-only table tabs).
   --sortable marks a tab whose drag can actually persist; the server writes it
   from the API's own update door (_build_saved_view_tabs). Drag is the strip's
   ONLY in-tab action — the delete ✕ and its constant widened right padding
   came off (Nick, 08-27: with no visible tab edges, every reserved pixel reads
   as dead space between labels), so deleting a view lives in the settings
   drawer's Delete row alone and every tab wears the same symmetric padding.
   The nav-level --manageable survives only as view-tab-strip.js's Sortable arm
   switch — no CSS keys on it, so hovering a tab that carries no chrome moves
   NOTHING (the old strip-level keying hid the kind glyph on every tab and the
   tabs without a grip jittered).

   Hovering a --sortable tab swaps the kind glyph for the drag grip in the SAME
   slot (grip renders before the glyph; exactly one of the two shows), so the
   tab never changes width mid-hover — but only because both SVGs declare the
   same 15×15 box (pinned by test_grip_and_kind_glyph_declare_the_same_size; an
   em-sized grip shipped once and every hover walked the label 2px). Only
   saved-view tabs carry the class, so the trailing "+" tab's __icon is safe by
   construction. */
/* The WHOLE tab is the drag handle — view-tab-strip.js dropped SortableJS's
   `handle:` because the grip is 15px and only appears on hover, so every grab
   landed on the label and nothing moved (Nick, 09-21: "the dragging for the
   view reordering is not working at all"). Dragging a label would otherwise
   sweep a text selection along under the cursor, so a draggable tab never
   selects. The grip stays as the hint that this tab moves. */
.global-tab--sortable,
.global-tab--grip-edge {
    -webkit-user-select: none;
    user-select: none;
}

.global-tab__grip {
    display: none;
    align-items: center;
    line-height: 1;
    color: var(--color-text-muted);
    cursor: grab;
}

.global-tab__grip:active {
    cursor: grabbing;
}

.global-tab--sortable:hover .global-tab__grip,
.global-tab--sortable:focus-within .global-tab__grip {
    display: inline-flex;
}

.global-tab--sortable:hover > .global-tab__icon,
.global-tab--sortable:focus-within > .global-tab__icon {
    display: none;
}

/* --grip-edge is --sortable's sibling for LABEL-ONLY tabs (the workers roster
   strip): with no kind glyph to swap with, an in-flow grip would walk the label
   on every hover — the exact wobble the swap exists to prevent. So the grip
   goes OUT of flow instead: absolute in constant widened LEFT padding, hidden
   by visibility (not display — it must hold its box) until hover/focus-within,
   so the tab measures the same hovered or not. These rules are (0,2,0)/(0,3,0),
   so they beat the base __grip display:none above without touching the
   --sortable variant. */
.global-tab--grip-edge {
    position: relative;
}

.global-tabs--neutral .global-tab--grip-edge {
    padding-left: var(--spacing-lg);
}

.global-tab--grip-edge .global-tab__grip {
    display: inline-flex;
    visibility: hidden;
    position: absolute;
    left: 0.45rem;
    top: 50%;
    transform: translateY(-50%);
}

.global-tab--grip-edge:hover .global-tab__grip,
.global-tab--grip-edge:focus-within .global-tab__grip {
    visibility: visible;
}

/* SortableJS ghost — the placeholder left in the strip while a tab is mid-drag. */
.global-tab--drag-ghost {
    opacity: 0.4;
}

/* Count chip after a tab label. Plain (brand tint) for a plain count; done/wait
   (success/warning tint) for progress. */
.global-tab__count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.25rem;
    padding: 0.05rem var(--spacing-xsm);
    border-radius: 999px;
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
    line-height: 1.4;
}

.global-tab__count--plain {
    background: var(--color-action-tint-pressed);
    color: var(--color-action);
}

.global-tab__count--done {
    background: color-mix(in srgb, var(--color-success) 15%, transparent);
    color: var(--color-success);
}

.global-tab__count--wait {
    background: color-mix(in srgb, var(--color-warning) 15%, transparent);
    color: var(--color-warning);
}

/* ── Card shell ── Keep the underline strip, but give it a white surface
   instead of letting the tabs float bare on the grey page. That floating strip
   read as "not standardized" on settings Profile / Referrals / Properties.

   Two shapes, and which one you want depends on the PANELS below the strip:

   1. BAR (the common case — seven of the eight carded strips). The shell wraps
      the strip ONLY; the panels keep their own `.card` surfaces underneath.
      Wrapping an already-carded panel in the shell too reads as a card inside
      a card.

          <div class="global-tab-card mb-3">
            <nav class="global-tabs">…</nav>
          </div>
          <div class="card">…panel…</div>

   2. SECTION. The shell wraps the strip AND a `__body`, for panels that are
      bare (a naked table, list, or form with no surface of its own).

          <div class="global-tab-card mb-3">
            <nav class="global-tabs">…</nav>
            <div class="global-tab-card__body">…bare form…</div>
          </div>

   Pick by what sits DIRECTLY below the strip, not by what the page is "made
   of" — the platform ledger was carded as BAR on the reasoning that its table
   is a `.card`, which is true but skips the bare filter form in between. A BAR
   shell over a bare element leaves the tabs alone in a full-width white bar
   with nothing under them, reading as a page banner rather than a tab strip.
   Ledger is the app's one SECTION today; see the note in that template.

   The test is whether the strip is the top-level thing a page is organised by.
   Status filter strips count: they sit at the top of the page and navigate
   between URLs, so they card like any other page-level strip. What does NOT
   card is a strip that already has a surface or belongs to one: the in-board
   view switchers (`--neutral`, dense controls on the board's own chrome), a
   strip built into a card's bottom edge (the opportunity record header), and
   one already nested inside a `.card` (ramp activity).

   Outer spacing is the caller's (`mb-3`/`mb-4`), matching how `.card` is spaced
   everywhere else.

   Radius is `--radius-card`, matching `.card` — the panel this shell sits
   directly on in the BAR shape. Take the same token as the neighbour, not the
   same number: whatever `--radius-card` resolves to (tokens.css) the shell
   and card move together. */
.global-tab-card {
    background: var(--color-card-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}

/* `.global-tab` already carries 0.9rem of its own horizontal padding, so the
   strip adds none — that padding IS the inset, and `__body` matches it so the
   body's content edge lines up with the first tab's label. `--spaced` is
   meaningless in here (the card's own margin does that job), so the shell
   neutralises it rather than making every caller remember to drop the modifier. */
.global-tab-card > .global-tabs,
.global-tab-card > * > .global-tabs {
    margin-bottom: 0;
}

/* BAR shape: with no body under it, the strip's underline seam would land on
   the card's own bottom border and read as a double rule. The active tab's 2px
   marker lives on the tab itself, so it survives dropping the seam — but the
   tab's -1px seam overlap must go with it, or `overflow: hidden` clips the
   bottom pixel of that marker off at the card edge. */
.global-tab-card > .global-tabs:last-child {
    border-bottom: 0;
}

.global-tab-card > .global-tabs:last-child .global-tab {
    margin-bottom: 0;
}

/* SECTION shape. `--flush` is for a body that supplies its own edge-to-edge
   content (a table that should meet the card's sides). */
/* The shell clips to its padding box, and `.global-tab` carries no horizontal
   margin — so the first tab sits ~1px from the shell's edge while its focus
   ring needs 4px (2px wide at a 2px offset). Outside the shell the ring is
   fine; inside, the left half of it was clipped away to nothing.

   Inset the ring rather than widen the shell or drop `overflow: hidden`: the
   ring then paints inside the tab's own box, where there is a comfortable
   0.9rem of padding, so it cannot be clipped no matter how tight the strip is
   against the card edge. Measured, not assumed — a clipped outline still
   reports its full `outline-width` in computed style, so this was found by
   counting painted pixels either side of the tab.

   Keyboard-only users are the ones who hit this, which makes it the kind of
   bug that goes unreported rather than unnoticed. */
.global-tab-card .global-tab:focus-visible {
    outline-offset: -2px;
}

.global-tab-card__body {
    padding: var(--spacing-md) var(--spacing-md);
}

/* ROW shape: the strip plus a right-hand control cluster on ONE line, for a
   control that belongs to a tab rather than to the page (the profile Overview
   edit pencil). It used to sit in its own right-aligned row *below* the shell,
   which left a band of empty page between the tabs and the first card and read
   as a stray floating button.

   This is not a place for page-level actions — those belong in the page
   header's actions cluster. Use it only where the control switches with the
   tab, and hide it (`x-show`) on the tabs it doesn't apply to.

   The shell's `overflow: hidden` has to come back off here. Hosting controls is
   this shape's whole job, and a control's menu or tooltip opens OUTSIDE the
   strip's box: the availability schedule picker's menu drops below its trigger
   and the at-limit tooltip on New availability opens under the button, and
   both painted straight into the clip — the click flipped the state and
   nothing appeared, at every width.

   Dropping it costs this shape nothing, because the clip is only ever a
   rounded-corner clip. What needs rounding off is a child that meets the
   card's sides: a SECTION's `--flush` body, or the strip's own seam in BAR.
   A ROW card has neither — no body at all, and `.global-tab` paints no
   background, just a 2px bottom marker that the rules below already pull back
   off the card's edge. The corners still round; there is simply nothing
   reaching them to clip. */
.global-tab-card--row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-smd);
    overflow: visible;
}

/* The nav stops being `:last-child` the moment actions sit beside it, so the
   BAR rules above stop matching and the strip's seam comes back as a double
   rule against the shell's own bottom border. Restate both halves — the seam
   and the tab's -1px overlap, which `overflow: hidden` would clip. */
.global-tab-card--row > .global-tabs {
    border-bottom: 0;
}

.global-tab-card--row > .global-tabs .global-tab {
    margin-bottom: 0;
}

/* Right inset matches the 0.9rem the first tab's own padding gives the left,
   so the cluster and the tab labels sit the same distance from the edges. */
.global-tab-card__actions {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
    flex: 0 0 auto;
    padding-right: var(--spacing-md);
}

@media (max-width: 575px) {
    /* One line does not hold both halves on a phone. The tabs are as narrow as
       their labels and the cluster is as wide as its buttons, and neither can
       give: with `flex: 0 0 auto` on the cluster and no wrap, the overflow left
       the strip, and the page itself scrolled 154px sideways with the cluster
       wedged into the tabs.

       Wrapping rather than a column, because the two halves fit side by side
       whenever they do fit — a two-tab strip next to one button has room at
       420px, and forcing a column would spend a row it doesn't need.

       The cluster keeps its right inset when it wraps, so a button below the
       tabs still lines up with the tab labels' other edge; and both halves grow
       to the full width so a wrapped cluster reads as its own row rather than a
       short box floating under the first tab. */
    .global-tab-card--row {
        flex-wrap: wrap;
        align-items: stretch;
    }

    .global-tab-card--row > .global-tabs {
        flex: 1 1 100%;
    }

    .global-tab-card--row > .global-tab-card__actions {
        flex: 1 1 100%;
        justify-content: flex-end;
        padding-bottom: var(--spacing-sm);
    }
}

/* ── Phone (<768px) ─────────────────────────────────────────────────────────
   A tab keeps its natural width and never wraps, so the row scrolls instead
   of squeezing (the scroller itself lives on the tabs container). LAST. */
@media (max-width: 767.98px) {
    .global-tab {
        flex: 0 0 auto;
        min-height: var(--control-h-touch);
        white-space: nowrap;
        scroll-snap-align: start;
    }

    /* This file's one non-generic rule: .global-tab-add is only ever rendered
       by the Opportunities tab strip (_view_tabs.html) — no other dashboard's
       tab strip carries it, so hiding it here touches nothing else.

       It creates a saved VIEW (a tab), a different door from the page's own
       primary "New" action (the labeled Add {vocab} button beside this strip,
       app/assignments/_new_opportunity_button.html) — but both render as a
       plain "+", crowded onto the same row with nothing between them at
       phone width, so a phone screenshot reads them as two doors to one
       action (the toolbar report this fixes named it a stray "+"). Add view
       is still a tap away on desktop, where the two buttons sit far enough
       apart to read as different controls; on phone the one unambiguous "+"
       is the labeled one. */
    .global-tab-add {
        display: none;
    }
}
