/* ==================== PAGE HEAD ====================
   The standing top of a list page: a search + actions bar, a six-slot KPI
   strip, a filter row and a result count.

   IT IS A COMPONENT, NOT A PAGE. Built for TMC Entities and deliberately
   generic, because more list tabs are coming and the brief was that this band
   must look and behave identically on all of them. Every page passes a config
   to PageHead.render(); nothing in this file knows what an entity is.

   The prefix is ph, one more feature namespace alongside ml/lk/ent/cs/xo/aa.
   Nothing here may style the shell — layout.css owns that, and a feature
   stylesheet restating a shell rule is a fault this project has already paid
   for twice.

   A CHIP THAT CANNOT BE PRODUCED IS DIMMED, NEVER FILLED. Same rule as the
   Executive Overview grey panels: the slot keeps its label and its position,
   the figure becomes an em dash, and the reason is on the tooltip. An invented
   number on a director screen is the worst thing this app could show. */

/* ---- the bar: search, then the actions ---- */
.ph-bar {
    display: flex; align-items: center; gap: .75rem;
    margin-bottom: .85rem; flex-wrap: wrap;
}
.ph-search {
    position: relative; flex: 1 1 320px; min-width: 0; max-width: 620px;
}
.ph-search > .bi-search {
    position: absolute; left: .8rem; top: 50%; transform: translateY(-50%);
    color: var(--text-dim); font-size: var(--fs-lg); pointer-events: none;
}
.ph-search input {
    /* the right padding used to reserve room for the Ctrl+K caps */
    width: 100%; height: 40px; padding: 0 .9rem 0 2.4rem;
    border-radius: 10px; border: 1px solid var(--border);
    background: var(--surface); color: var(--text); font-size: var(--fs-lg);
    transition: border-color .14s ease, box-shadow .14s ease;
}
.ph-search input::placeholder { color: var(--text-dim); }
.ph-search input:focus {
    outline: none; border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-weak);
}
.ph-actions { display: flex; align-items: center; gap: .5rem; margin-left: auto; }
.ph-btn {
    display: inline-flex; align-items: center; gap: .4rem; height: 40px;
    padding: 0 .95rem; border-radius: 9px; font-size: var(--fs-md); font-weight: var(--fw-medium);
    border: 1px solid var(--border); background: var(--surface); color: var(--text);
    cursor: pointer; white-space: nowrap;
    transition: background .14s ease, border-color .14s ease, color .14s ease;
}
.ph-btn:hover { background: var(--surface-2); border-color: var(--accent-line); }
.ph-btn.is-primary {
    background: var(--accent-fill); border-color: var(--accent-fill);
    color: var(--accent-on); font-weight: var(--fw-bold);
}
.ph-btn.is-primary:hover { filter: brightness(1.06); }
.ph-btn i { font-size: var(--fs-lg); }

/* ---- the KPI strip ----
   auto-fit rather than a fixed six columns, so the same component carries four
   chips on a narrower tab without a second breakpoint per page. */
.ph-kpis {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(196px, 1fr));
    gap: .7rem; margin-bottom: .85rem;
}
.ph-kpi {
    background: var(--surface); border: 1px solid var(--border);
    border-radius: 11px; padding: .7rem .85rem .75rem;
    display: flex; flex-direction: column; min-width: 0;
    /* A container, so the chip decides by ITS OWN width what to give up - see
       the query at the foot of the strip rules. */
    container-type: inline-size;
}
.ph-kpi-h {
    display: flex; align-items: center; gap: .3rem; margin-bottom: .3rem;
    font-size: var(--fs-2xs); font-weight: var(--fw-bold); letter-spacing: .02em;
    color: var(--text-soft); white-space: nowrap; overflow: hidden;
}
.ph-kpi-h .nm { overflow: hidden; text-overflow: ellipsis; }
/* The optional icon plate - the Home KPI card's. Drawn only when a page passes
   `icon`, so a chip without one renders exactly as before. */
.ph-kpi-ico {
    width: 32px; height: 32px; flex: 0 0 32px; border-radius: 9px;
    display: grid; place-items: center; font-size: 1rem;
    background: var(--accent-weak); color: var(--accent-ink);
}
.ph-kpi.is-off .ph-kpi-ico { background: var(--surface-3); color: var(--text-dim); }
.ph-kpi-h .bi-info-circle {
    font-size: var(--fs-xs); color: var(--text-dim); flex: 0 0 auto; cursor: help;
}
.ph-kpi-b { display: flex; align-items: flex-end; gap: .5rem; min-width: 0; }
.ph-kpi-t { min-width: 0; flex: 1 1 auto; }
.ph-kpi-v {
    font-size: 1.32rem; font-weight: var(--fw-bold); letter-spacing: -.03em; line-height: 1.15;
    font-variant-numeric: tabular-nums; color: var(--text);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ph-kpi-s {
    font-size: var(--fs-2xs); margin-top: .18rem; color: var(--text-dim);
    /* Clipped mid-word this said less than nothing — "7,366 prospecti…". Two
       lines, then ellipsis, so a long caption degrades legibly. */
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden; line-height: 1.3;
}
.ph-kpi-s.up   { color: var(--ok-ink,  var(--ok));  font-weight: var(--fw-medium); }
.ph-kpi-s.down { color: var(--bad-ink, var(--bad)); font-weight: var(--fw-medium); }
/* the little picture on the right — never the thing carrying the number */
.ph-kpi-viz { flex: 0 0 auto; display: flex; align-items: flex-end; }
.ph-kpi-viz svg { display: block; overflow: visible; }

/* THE DECORATION GIVES WAY, NEVER THE FIGURE. A full-money figure beside a
   64px sparkline needs ~250px of chip, and auto-fit hands out 237px at a
   1,600px window and 198px at 1,366 - so the headline read "$300,083,9..." on
   three chips at once, the one thing on the chip that must never be cut. The
   picture only repeats what the figure says (see the note in page-head.js), so
   it goes first; below that the figure steps down a size rather than
   ellipsising. Same answer the entity record's KPI cards reached under 210px.
   On a browser without container queries nothing here applies and the chip
   renders exactly as it did before. */
@container (max-width: 250px) {
    .ph-kpi-viz { display: none; }
}
@container (max-width: 190px) {
    .ph-kpi-v { font-size: var(--fs-xl); }
}

/* the unavailable state: the slot keeps its size and its label */
.ph-kpi.is-off { background: var(--surface-2); border-style: dashed; }
.ph-kpi.is-off .ph-kpi-v { color: var(--text-dim); font-weight: var(--fw-medium); }
.ph-kpi.is-off .ph-kpi-h { color: var(--text-dim); }

/* ---- the filter row ---- */
.ph-filters {
    display: flex; align-items: flex-end; gap: .6rem; flex-wrap: wrap;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: 11px; padding: .65rem .75rem; margin-bottom: .7rem;
}
/* 200ms on the filter controls, up from 140. THE BAND IS THE ONE PLACE IN THIS
   APP WHERE A READER CHANGES SOMETHING AND WATCHES THE ROWS BELOW REDRAW, and a
   140ms colour change under the pointer had already finished before the eye
   arrived - so the control that was just set looked the same as the one beside
   it. 200 is long enough to register as the control answering and short enough
   that it is over before the list is. Colour only here; the press (a
   transform) is in motion.css with the rest of the press vocabulary, and both
   are switched off in the reduced-motion block at the foot of this file. */
.ph-fbtn {
    width: 38px; height: 38px; flex: 0 0 38px; border-radius: 9px;
    border: 1px solid var(--border); background: var(--surface-2);
    color: var(--text-soft); display: grid; place-items: center; cursor: pointer;
    transition: background .2s ease, color .2s ease, border-color .2s ease;
}
.ph-fbtn:hover { background: var(--accent-weak); border-color: var(--accent-line); color: var(--accent); }
.ph-f { display: flex; flex-direction: column; gap: .18rem; min-width: 0; flex: 1 1 130px; }
.ph-f > label {
    font-size: var(--fs-2xs); font-weight: var(--fw-medium); color: var(--text-dim);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ph-f > select, .ph-f > input {
    height: 34px; border-radius: 8px; border: 1px solid var(--border);
    background: var(--surface); color: var(--text); font-size: var(--fs-md);
    padding: 0 .55rem; min-width: 0; width: 100%;
    /* The .is-set state below is a border, a fill and a weight change, and it
       arrived as a hard cut - so a filter you had just set looked no different
       from one that had always been set. 200ms, the band's figure. */
    transition: background .2s ease, border-color .2s ease, box-shadow .2s ease;
}
.ph-f > select:focus, .ph-f > input:focus {
    outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-weak);
}
/* a filter holding a non-default value announces itself, or Clear All is a
   button whose purpose nobody can see */
.ph-f.is-set > select, .ph-f.is-set > input {
    border-color: var(--accent); background: var(--accent-weak); font-weight: var(--fw-medium);
}
/* not wired up yet — the slot holds its place and says why on hover. A
   disabled control receives no mouse events, so the tooltip goes on the WRAPPER
   and not on the <select>, or it could never open. */
.ph-f.is-off { opacity: .55; cursor: help; }
.ph-f.is-off > select { pointer-events: none; background: var(--surface-3); }

/* a slot the page fills itself — the band keeps the label and the spacing */
.ph-f-custom { flex: 0 0 auto; }

.ph-ftail { display: flex; align-items: center; gap: .5rem; margin-left: auto; }
.ph-ftail .ph-btn { height: 34px; font-size: var(--fs-sm); }

/* ---- the count line ---- */
.ph-count {
    display: flex; align-items: center; gap: .5rem;
    margin-bottom: .5rem; font-size: var(--fs-sm); color: var(--text-soft);
}
/* said when the page filtered rows the server did not, so the total and the
   rows on screen can be reconciled instead of quietly disagreeing */
.ph-note {
    font-size: var(--fs-xs); color: var(--warn-ink, var(--warn));
    background: var(--warn-weak); border: 1px solid var(--warn-line);
    padding: .08rem .45rem; border-radius: 999px;
}
.ph-count b { color: var(--text); font-weight: var(--fw-bold); font-variant-numeric: tabular-nums; }
.ph-pager { display: flex; gap: .3rem; margin-left: auto; }
.ph-pager button {
    width: 30px; height: 30px; border-radius: 8px; display: grid; place-items: center;
    border: 1px solid var(--border); background: var(--surface); color: var(--text-soft);
    /* The opacity step to .38 when an arrow runs out of pages is a state and
       transitions with the rest of it. The press is a transform and lives in
       motion.css, which also declines to move a DISABLED arrow - it is the one
       control on this row that cannot answer. */
    cursor: pointer; transition: background .2s ease, color .2s ease, opacity .2s ease;
}
.ph-pager button:hover:not(:disabled) { background: var(--accent-weak); color: var(--accent); }
.ph-pager button:disabled { opacity: .38; cursor: default; }

@media (max-width: 767.98px) {
    .ph-actions { margin-left: 0; width: 100%; }
    .ph-actions .ph-btn { flex: 1 1 0; justify-content: center; }
}
/* TWO ACROSS ON A PHONE, NOT ONE. The 196px track minimum put six chips in a
   single column at 390px - ~590px of scrolling before the first filter, and the
   list the chips summarise two screens further down. Two across halves that;
   the container queries above then drop the picture and step the figure down,
   so a full "$300,083,928" still fits a 175px chip. */
@media (max-width: 575.98px) {
    .ph-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .5rem; }
    .ph-kpi { padding: .6rem .7rem .65rem; }
}

/* A chip that opens the rows it counted says so before it is clicked. It lifts
   2px, the figure the house hover takes, and it takes the SAME treatment on
   :focus-visible — a keyboard reader gets the affordance a pointer gets, which
   is the whole point of adding it here rather than only on :hover. Only
   transform and box-shadow move, so nothing around the chip reflows; the strip
   is a grid and a lifted chip keeps its cell.

   THIS COMMENT USED TO CLAIM "the same 2px every other clickable card in this
   app lifts", AND ON THE ONE PAGE WITH KPI CHIPS THAT WAS UNTRUE.
   entities.css carried `#page-entities .ph-kpi:hover { translateY(-3px) }` at
   (1,2,0), which outranks this rule's (0,3,0) — so hover lifted 3px there and
   :focus-visible lifted 2, at 250ms rather than 160. The override is retired
   (see the note at `#page-entities .ph-kpi`), so this is now the only rule that
   moves a KPI chip anywhere in the app. A claim about every page has to be
   checked on every page: a more specific rule elsewhere beats a general one
   here whatever the load order says.

   --lift-* live in motion.css, which loads LAST, so every other stylesheet
   names them with a fallback — the pattern company-chooser.css sets out. The
   transition is switched off under reduced motion below, and motion.css
   neutralises the transform there as well, so neither file is the only thing
   standing between a reduced-motion reader and a moving page. */
.ph-kpi.ph-click { cursor: pointer; transition: transform .16s var(--ease), box-shadow .16s var(--ease), border-color .16s ease; }
.ph-kpi.ph-click:hover,
.ph-kpi.ph-click:focus-visible {
    transform: translateY(-2px);
    box-shadow: var(--lift-2, 0 6px 20px rgba(0, 0, 0, .16));
    border-color: var(--accent-line);
}
.ph-kpi.ph-click:hover .ph-kpi-v,
.ph-kpi.ph-click:focus-visible .ph-kpi-v { text-decoration: underline; text-underline-offset: .18em; }
@media (prefers-reduced-motion: reduce) {
    .ph-kpi.ph-click { transition: none; }
    /* The 200ms state transitions added to the band's controls on 2026-09-21.
       The values they transition BETWEEN are unchanged, so a reduced-motion
       reader gets the same band with the steps taken instantly. motion.css
       neutralises their :active transforms in its own reduce block. */
    .ph-fbtn, .ph-pager button, .ph-f > select, .ph-f > input { transition: none; }
}
