/* ══════════════════════════════════════════════════════════════════════════════════════════════════
   LOADING STATES (2026-10-07, owner-approved): skeletons, a real-fraction top progress bar, calm retry.
   ⛔ ONE RULE: an element shows a skeleton OR a real value. "0" and "—" are values (they mean zero and
   "unknown after asking"); they are never placeholders. The owner's screenshot showed "—" live jobs and
   "0 strong matches" on every reload, re-open and slow network: the page claimed numbers it did not have.
   Pieces (JS in 19-loading.js + the loaders in 14-app.js):
     .skv         a value not known yet. Empty element, reserved width (--skw), its own line box (a zero-width
                 space), so the real value lands in the same box: no layout shift.
     (labels)    a tile's label is drawn as a bar while its number is a skeleton (same text, same geometry).
     .sk-stale   a value still on screen after a long absence while it is being re-read (dimmed, a slow pulse).
     .sk-in      the settle animation a value plays once when it replaces its skeleton.
     .kw-busy    a form that is not filled yet (Settings rules, Application details): not editable, drawn as bars.
     .sk-note    "Taking longer than usual · Retry" (8 s) / "Couldn't load · Retry" (an error; retried on its own).
     #kwProg     the 2 px bar at the very top: done boot requests / expected boot requests, never backwards.
   Shimmer = one translucent sheen moved by transform on a pseudo-element (compositor only). Reduced motion: static.
   ══════════════════════════════════════════════════════════════════════════════════════════════════ */
:root{--sk-base:rgba(23,23,43,.065);--sk-sheen:rgba(255,255,255,.55);--sk-dur:1.6s}
.app{--sk-base:rgba(23,23,43,.065);--sk-sheen:rgba(255,255,255,.6)}
/* the dark results band */
.app .holo,.holo{--sk-base:rgba(255,255,255,.085);--sk-sheen:rgba(255,255,255,.11)}
.app .holo.holo--lime,.trial-pill:not(.tp-subbed){--sk-base:rgba(23,23,43,.09);--sk-sheen:rgba(255,255,255,.45)}
#statForms{--sk-base:rgba(245,255,171,.10);--sk-sheen:rgba(245,255,171,.14)}
[data-theme="dark"] .app{--sk-base:rgba(255,255,255,.085);--sk-sheen:rgba(255,255,255,.11)}

/* ── value skeleton ── */
.skv{display:inline-block;width:var(--skw,3.2ch);max-width:100%;color:transparent!important;-webkit-text-fill-color:transparent;
  background:var(--sk-base)!important;border-color:transparent!important;position:relative;
  /* ⛔ no overflow:hidden on an inline-block: it moves the box's baseline to its bottom edge and the line grows
     (the hero band was 74 px taller while loading). clip-path clips the sheen instead. */
  clip-path:inset(var(--skin,17%) 0 round var(--skr,6px));vertical-align:baseline;user-select:none;pointer-events:none;
  text-shadow:none!important}
:is(div,p,li).skv{display:block}
.skv::before{content:"\200b"}
.skv::after,.jcard.skel .btn::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(90deg,transparent 0,var(--sk-sheen) 50%,transparent 100%);
  transform:translateX(-100%);animation:kw-sk var(--sk-dur) cubic-bezier(.4,0,.2,1) infinite;will-change:transform}
@keyframes kw-sk{0%{transform:translateX(-100%)}62%,100%{transform:translateX(100%)}}

/* a tile's label is drawn as a bar while its number is unknown (keeps the exact text geometry) */
.hmini:has(> .hmini-n.skv) > .hmini-l,
.holo-hero2-main:has(#statForms.skv) #statFormsLabel{color:transparent!important;-webkit-text-fill-color:transparent;background:var(--sk-base);
  position:relative;overflow:hidden;width:fit-content;max-width:100%;clip-path:inset(16% 0 round 5px);user-select:none}
.hmini:has(> .hmini-n.skv) > .hmini-l::after,.holo-hero2-main:has(#statForms.skv) #statFormsLabel::after{content:"";position:absolute;inset:0;
  background:linear-gradient(90deg,transparent 0,var(--sk-sheen) 50%,transparent 100%);transform:translateX(-100%);
  animation:kw-sk var(--sk-dur) cubic-bezier(.4,0,.2,1) infinite;will-change:transform}
/* the two-line sentence under the hero number: one bar per line (inline fragments), same text, same height */
.holo-hero2-main:has(#statForms.skv) .hh2-sub > span{color:transparent;-webkit-text-fill-color:transparent;user-select:none;
  background:linear-gradient(var(--sk-base),var(--sk-base)) 0 55%/100% 58% no-repeat;
  -webkit-box-decoration-break:clone;box-decoration-break:clone}
.holo-hero2-main:has(#statForms.skv) #applyLive{visibility:hidden}

/* typical widths, so the value lands where its skeleton was */
#statForms.skv{--skw:2.1ch;--skin:12%;--skr:12px}
.hmini-n.skv{--skw:6.6ch;--skin:16%}
#statStrong.skv{--skw:3.8ch}
#statFeed.skv{--skw:4.8ch}
.holo-reach b.skv{--skw:6ch}
#jobCountN.skv{--skw:3.4ch;--skin:14%}
#jobCountL.skv{--skw:4.6ch}
.seg-n.skv{--skw:3ch;--skin:22%;vertical-align:-1px}
.seg-n.skv:empty{display:inline-block}   /* 03-app.css hides an empty count; a skeleton is not empty */
#autoChip .skv{--skw:2.6ch;--skin:20%;margin-left:4px;vertical-align:-1px}
.kwb-cell b.skv{--skw:9ch}
.mi-addrline code.skv{--skw:24ch;--skin:10%}
.nav-count.skv{min-width:18px;width:18px;padding:0;--skin:0%;--skr:9px;--sk-base:rgba(23,23,43,.08)}
/* ⛔ [hidden] lost to .nav-count{display:inline-flex}: an empty lime dot while loading and a "0" badge after
   (the baseline screenshot of 2026-10-07). Hidden means hidden. */
.nav-count[hidden]{display:none!important}

/* the trial pill reserves its place from the first frame (the sidebar foot used to jump when it appeared) */
.trial-pill.tp-sk{background:transparent;border-color:var(--line,rgba(23,23,43,.12));pointer-events:none}
.trial-pill.tp-sk .tp-fg{stroke:transparent}
.trial-pill.tp-sk .tp-bg{stroke:var(--sk-base)}
.trial-pill.tp-sk .tp-txt b,.trial-pill.tp-sk .tp-txt span{display:block}
.trial-pill.tp-sk .tp-txt b{--skw:7ch}
.trial-pill.tp-sk .tp-txt span{--skw:9.5ch;margin-top:2px}

/* a value that arrives: a short settle, never a count from zero */
/* ⛔ fill-mode BACKWARDS only: "both" pinned opacity:1 after the animation, so a later stale mark could not dim it */
.sk-in{animation:kw-sk-in .42s cubic-bezier(.2,.8,.2,1) backwards}
@keyframes kw-sk-in{from{opacity:0;transform:translateY(.12em);filter:blur(3px)}to{opacity:1;transform:none;filter:none}}
span.sk-in,b.sk-in{display:inline-block}

/* a value kept on screen while it is re-read after a long absence */
.sk-stale{animation:kw-sk-stale 1.6s ease-in-out infinite}
@keyframes kw-sk-stale{0%,100%{opacity:.62}50%{opacity:.38}}

/* ── job-card skeletons (the real card's geometry: title row, meta row, three actions) ── */
.jcard.skel{pointer-events:none;animation:none!important}
.jcard.skel .jtitle .skv{--skw:min(var(--w1,58%),36ch);--skin:20%}
.jcard.skel .jmeta .skv{--skin:22%}
.jcard.skel .jmeta .skv:nth-child(1){--skw:var(--w2,10ch)}
.jcard.skel .jmeta .skv:nth-child(2){--skw:var(--w3,13ch)}
.jcard.skel .jmeta .skv:nth-child(3){--skw:7ch}
.jcard.skel .jmeta .skv:nth-child(4){--skw:9ch}
.jcard.skel .btn{background:var(--sk-base)!important;color:transparent!important;border-color:transparent!important;
  box-shadow:none!important;position:relative;overflow:hidden;transform:none!important}
.jobs-grid .jcard.skel:nth-child(3n+2){--w1:44%;--w2:8ch;--w3:15ch}
.jobs-grid .jcard.skel:nth-child(3n){--w1:66%;--w2:12ch;--w3:10ch}
.jobs-grid .jcard.skel:nth-child(n+4){opacity:.75}
.jobs-grid .jcard.skel:nth-child(n+6){opacity:.5}

/* ── list skeletons (Sent CVs, Tracker, Inbox, Answers) ── */
.sk-list{pointer-events:none}
.sk-row{display:flex;align-items:center;gap:16px;padding:14px 16px;border-bottom:1px solid var(--line-soft)}
.sk-row:last-child{border-bottom:0}
.sk-row .sk-col{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:2px}
.sk-row .skv{font-size:13px}
.sk-row .skv.sk-l1{--skw:min(var(--w1,46%),30ch);font-weight:800}
.sk-row .skv.sk-l2{--skw:min(var(--w2,64%),44ch);font-size:12px}
.sk-row .skv.sk-pill{--skw:11ch;--skr:20px;--skin:10%;flex:0 0 auto}
.sk-row .skv.sk-btn{--skw:9ch;--skr:8px;--skin:6%;flex:0 0 auto;font-size:15px}
.sk-row:nth-child(3n+2){--w1:38%;--w2:56%}
.sk-row:nth-child(3n){--w1:52%;--w2:72%}
.board.sk-list .bcard{min-height:74px}
.board.sk-list .bcard .skv{display:block;font-size:12px}
.board.sk-list .bcard .skv.sk-l1{--skw:60%} .board.sk-list .bcard .skv.sk-l2{--skw:85%;margin-top:4px}

/* ── a form that is not filled yet ── */
.kw-busy :is(input,select,textarea){color:transparent!important;-webkit-text-fill-color:transparent;background:var(--sk-base)!important;
  border-color:transparent!important;box-shadow:none!important;pointer-events:none;animation:kw-sk-pulse 1.6s ease-in-out infinite}
.kw-busy :is(input,textarea)::placeholder{color:transparent}
.kw-busy :is(.chipbox,.seg,.pill,.ad-work>*,.ws-wrap){pointer-events:none;animation:kw-sk-pulse 1.6s ease-in-out infinite}
.kw-busy :is(.chipbox .chips,.seg .seg-opt,.ad-work>*){color:transparent!important}
.kw-busy .seg-thumb{opacity:0}
/* the plan card: its buttons depend on the plan, so they wait as bars too */
.kwb.kw-busy .kwb-btn{background:var(--sk-base)!important;color:transparent!important;border-color:transparent!important;
  box-shadow:none!important;pointer-events:none;animation:kw-sk-pulse 1.6s ease-in-out infinite}
.kwb.kw-busy .kwb-fill{width:0!important}
.bcol-head .cnt.skv{min-width:var(--skw)}
@keyframes kw-sk-pulse{0%,100%{opacity:1}50%{opacity:.55}}

/* ── calm retry / slow note ── */
.sk-note{display:inline-flex;align-items:center;gap:6px;font-size:12px;font-weight:600;color:var(--ink-dim);letter-spacing:0;
  text-transform:none;line-height:1.2;white-space:nowrap}
.sk-note[hidden]{display:none!important}
.sk-note i{width:6px;height:6px;border-radius:50%;background:currentColor;opacity:.55;flex:0 0 auto}
.sk-note.err i{background:var(--warn,#e0b64a);opacity:1}
.sk-note .sk-retry{background:none;border:0;padding:2px 0;margin:0;font:inherit;font-weight:700;color:inherit;cursor:pointer;
  text-decoration:underline;text-underline-offset:3px;text-decoration-color:currentColor}
.sk-note .sk-retry:hover{color:var(--ink)}
#holo > .sk-note{position:absolute;top:14px;right:16px;z-index:3;color:rgba(255,255,255,.66)}
#holo > .sk-note .sk-retry:hover{color:#fff}
#jobsEmpty .sk-note,.sk-note.block{display:flex;justify-content:center;padding:14px 0}
.kwb > .sk-note{float:right;margin-top:2px}

/* ── 2 px top progress bar: real fractions of the boot requests ── */
.kw-prog{position:fixed;top:0;left:0;right:0;height:2px;z-index:2147483000;pointer-events:none;transform-origin:0 50%;
  transform:scaleX(0);opacity:0;background:var(--lime,#F5FFAB);
  transition:transform .45s cubic-bezier(.2,.8,.2,1),opacity .35s ease .15s}
body:has(#app:not(.hide)) .kw-prog,body:has(#bootSplash) .kw-prog{background:var(--navy,#17172B)}
.kw-prog.on{opacity:.85}
.kw-prog.done{opacity:0;transition:transform .25s ease,opacity .45s ease .2s}

/* ── boot placeholder → app: the same paper, the same sidebar, so the hand-over is not a flash ── */
.boot-splash{background:#FAFAF7;color:rgba(23,23,43,.5);z-index:50;transition:opacity .22s ease}
.boot-splash.out{opacity:0}
.boot-splash .bs-side{position:absolute;left:0;top:0;bottom:0;width:236px;background:#fff;border-right:1px solid rgba(23,23,43,.12);
  padding:22px 14px 16px}
.boot-splash .brand{color:var(--navy,#17172B);margin:4px 8px 24px}
.boot-splash .bs-main{position:absolute;left:236px;right:0;top:0;bottom:0;display:flex;align-items:center;justify-content:center;
  font-size:13px;font-weight:600;letter-spacing:.01em}
@media(max-width:820px){
  .boot-splash .bs-side{right:0;bottom:auto;width:auto;border-right:0;border-bottom:1px solid rgba(23,23,43,.12);padding:12px 16px;
    box-shadow:0 1px 0 rgba(0,0,0,.04)}
  .boot-splash .brand{margin:0;font-size:15px}
  .boot-splash .bs-main{left:0;top:49px}
}
.app.kw-enter > main{animation:kw-enter .26s ease-out both}
@keyframes kw-enter{from{opacity:0}to{opacity:1}}

@media (prefers-reduced-motion:reduce){
  .skv::after,.jcard.skel .btn::after,.hmini-l::after,#statFormsLabel::after{animation:none;display:none}
  .sk-stale{animation:none;opacity:.5}
  .sk-in,.app.kw-enter > main{animation:none}
  .kw-busy :is(input,select,textarea,.chipbox,.seg,.pill,.ad-work>*,.ws-wrap,.kwb-btn){animation:none;opacity:.7}
  .kw-prog,.boot-splash{transition:none}
}
/* a feed being built for the first time has its own progress screen: the skeletons wait without a sheen */
body.kw-building .skv::after{animation:none;opacity:0}
