/* ============================================================================
   EMPLOYEE PORTAL — /employee-login
   Loaded AFTER style.css, which supplies :root tokens, .btn and .fpm-credit.
   Nothing in here is used by the marketing page, and nothing here overrides a
   marketing-page selector, so the two can change independently.

   Served under css/* = max-age:0, must-revalidate (see vercel.json), so this
   file needs no ?v= cache-bust — unlike /assets/*, which is immutable.
   ========================================================================== */

.portal{background:var(--ink);color:var(--bone);min-height:100vh}
/* The UA stylesheet's [hidden]{display:none} is a plain type-less rule, so ANY
   author display declaration outranks it — .gate{display:grid} below meant
   gate.hidden=true did nothing and the sign-in card stayed on screen above the
   dashboard after submit. This has to come first and it has to be !important,
   because .gate/.app set display unconditionally. */
[hidden]{display:none!important}

/* ---------- loading ---------- */
/* Shown only until the first getSession() resolves (see js/portal.js) — a
   deliberately quiet placeholder, not a spinner-heavy splash, because it is
   normally on screen for well under a second. */
.ploading{min-height:100vh;display:grid;place-items:center;padding:20px}
.ploading p{margin:0;color:var(--bone-dim);font-family:var(--display);font-weight:600;
  font-size:.95rem}

/* ---------- gate ---------- */
/* --pbanner-h no longer gets set by anything — the concept banner this
   variable measured was removed once the page went from mockup to a real
   Supabase-backed login (see the HTML's header comment on .gate). The 0px
   fallback is therefore what's actually in effect; the var() is left in
   place rather than hardcoding 100vh/0 so a future banner-style notice could
   reintroduce itself here without a second CSS change. */
.gate{min-height:calc(100vh - var(--pbanner-h,0px));display:grid;place-items:center;
  padding:clamp(24px,6vw,64px) 20px}
.gate__card{width:100%;max-width:430px;background:var(--ink-2);border:1px solid var(--ink-3);
  border-radius:22px;padding:clamp(26px,5vw,40px);text-align:center}
.gate__brand{display:inline-flex;align-items:center;gap:.6rem;text-decoration:none;margin-bottom:1.4rem}
.gate__logo{height:96px;width:auto;display:block}
.gate__card h1{font-family:var(--display);font-weight:800;font-size:1.85rem;color:var(--bone);
  letter-spacing:-.01em}
.gate__sub{margin:.7rem 0 0;color:var(--bone-dim);font-size:.95rem;line-height:1.5}
.gate__form{display:grid;gap:1rem;margin-top:1.9rem;text-align:left}
.gf{display:grid;gap:.4rem}
.gf label{font-family:var(--display);font-weight:600;font-size:.85rem;color:var(--bone)}
/* Shared by the sign-in gate, the admin resource form and the change-password
   card — every real text/email/password/url/select/textarea field on this
   page uses .gf, so they all look and focus identically. */
.gf input,.gf select,.gf textarea{width:100%;background:var(--ink);border:1px solid var(--ink-3);
  border-radius:11px;padding:.8rem .95rem;color:var(--bone);font:inherit;font-size:.95rem}
.gf textarea{resize:vertical;min-height:4.5rem}
.gf input:focus-visible,.gf select:focus-visible,.gf textarea:focus-visible{border-color:var(--purple-lift)}
.gf input:disabled,.gf select:disabled,.gf textarea:disabled{color:var(--grey);cursor:not-allowed;opacity:.85}
.gf input:disabled::placeholder{color:var(--grey);opacity:1}
/* Magenta here is NOT a budget regression — style.css already assigns magenta
   the form-error role (.field input:user-invalid, .form-status.err). This is
   the same semantic use on a page that is noindex and off the marketing
   funnel, not a new decorative accent. Reused below for .rf-err and .pw-err. */
.gate__err,.rf-err,.pw-err{margin:0;padding:.6rem .8rem;border-radius:9px;font-size:.85rem;
  background:rgba(232,29,117,.12);border:1px solid var(--magenta);color:var(--magenta-lift)}
.gate__btn{justify-content:center;width:100%;margin-top:.3rem}
.gate__back{display:inline-block;margin-top:1.6rem;font-size:.85rem;color:var(--bone-dim);
  text-decoration:none}
.gate__back:hover{color:var(--purple-lift)}

/* ---------- top bar ---------- */
/* See the --pbanner-h comment on .gate above: nothing sets this variable any
   more, so the 0px fallback is what actually applies and the bar sits flush
   at the very top of the viewport. */
.ptb{position:sticky;top:var(--pbanner-h,0px);z-index:50;background:rgba(23,23,28,.92);
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
  border-bottom:1px solid var(--ink-3)}
.ptb__in{max-width:1180px;margin:0 auto;padding:.75rem 20px;display:flex;align-items:center;gap:.85rem}
.ptb__brand{display:inline-flex;align-items:center;gap:.5rem;text-decoration:none}
.ptb__logo{height:44px;width:auto;display:block}
.ptb__div{width:1px;height:28px;background:var(--ink-3)}
.ptb__ctx{font-family:var(--display);font-weight:700;font-size:.9rem;color:var(--bone-dim)}
.ptb__right{margin-left:auto;display:flex;align-items:center;gap:.9rem}
.ptb__user{display:inline-flex;align-items:center;gap:.5rem}
.ptb__avatar{width:28px;height:28px;border-radius:50%;background:var(--purple);color:#fff;
  display:grid;place-items:center;font-family:var(--display);font-weight:700;font-size:.72rem}
.ptb__uname{font-size:.88rem;color:var(--bone-dim)}
.ptb__out{background:none;border:1px solid var(--ink-3);border-radius:9px;padding:.4rem .8rem;
  color:var(--bone-dim);font:inherit;font-size:.83rem;cursor:pointer;white-space:nowrap}
.ptb__out:hover{color:var(--bone);border-color:var(--purple-lift)}
@media (max-width:560px){.ptb__ctx,.ptb__uname{display:none}}

/* ---------- canvas ---------- */
.pcanvas{padding:clamp(28px,5vw,52px) 0 clamp(40px,6vw,72px)}
.pwrap{max-width:1180px;margin:0 auto;padding:0 20px}
.phead h2{font-family:var(--display);font-weight:800;font-size:clamp(1.7rem,3.6vw,2.4rem);
  color:var(--bone);letter-spacing:-.01em}
.phead p{margin:.45rem 0 0;color:var(--bone-dim);font-size:.98rem;max-width:60ch}

/* ---------- admin bar / flag ---------- */
.padmin-bar{display:flex;flex-wrap:wrap;align-items:center;gap:.75rem .9rem;margin-top:1.6rem}
.padmin-flag{flex-basis:100%;margin:0;padding:.7rem .95rem;background:rgba(232,29,117,.1);
  border:1px solid var(--magenta);border-radius:10px;color:var(--magenta-lift);font-size:.85rem;
  line-height:1.45}

/* ---------- admin: add/edit resource form ---------- */
.padmin-panel{max-width:560px;background:var(--ink-2);border:1px solid var(--ink-3);
  border-radius:16px;padding:clamp(20px,3.4vw,30px);margin-top:1.4rem}
.padmin-panel h4{font-family:var(--display);font-weight:700;font-size:1.05rem;color:var(--bone);margin:0 0 1.2rem}
.padmin-panel form{display:grid;gap:1rem}
.rf-target{border:1px solid var(--ink-3);border-radius:11px;padding:.85rem .95rem;display:grid;gap:.55rem;margin:0}
.rf-target legend{font-family:var(--display);font-weight:600;font-size:.85rem;color:var(--bone);padding:0}
.rf-target__opt{display:flex;align-items:center;gap:.55rem;font-size:.92rem;color:var(--bone-dim);cursor:pointer}
.rf-target__opt input{accent-color:var(--purple-lift)}
.rf-file-current{margin:.5rem 0 0;font-size:.82rem;color:var(--bone-dim);line-height:1.4}
.rf-actions{display:flex;gap:.75rem;flex-wrap:wrap;margin-top:.3rem}
.rf-actions .btn{flex:1;justify-content:center;min-width:9rem}

.psec{font-family:var(--display);font-weight:700;font-size:.8rem;letter-spacing:.1em;
  text-transform:uppercase;color:var(--purple-lift);margin:2.6rem 0 1rem}
/* Dynamic sections wrap their h3.psec in .psec-row so an admin's rename/
   delete buttons can sit on the same line — .psec-block supplies the 2.6rem
   gap above the whole row instead, so the heading's own margin is zeroed out
   here to avoid stacking both. The static "Need a Person" / "Account"
   headings elsewhere on the page are bare h3.psec with no wrapper, so they
   still get the plain margin above unchanged. */
.psec-block{margin:2.6rem 0 0}
.psec-row{display:flex;align-items:baseline;flex-wrap:wrap;gap:.75rem 1rem;margin-bottom:1rem}
.psec-row .psec{margin:0}
.psec-admin{display:flex;gap:.5rem;flex-wrap:wrap}
.psec-admin__btn{background:none;border:1px solid var(--ink-3);border-radius:7px;padding:.3rem .65rem;
  color:var(--bone-dim);font:inherit;font-size:.76rem;cursor:pointer;white-space:nowrap}
.psec-admin__btn:hover{color:var(--bone);border-color:var(--purple-lift)}
.psec-admin__btn--danger:hover{color:var(--magenta-lift);border-color:var(--magenta)}
.psec-empty{margin:0;padding:1rem 1.15rem;background:var(--ink-2);border:1px dashed var(--ink-3);
  border-radius:12px;color:var(--bone-dim);font-size:.88rem;line-height:1.5}

/* ---------- resource rows ---------- */
.rgrid{display:grid;grid-template-columns:1fr 1fr;gap:.85rem}
/* Admin rows carry a second, wider toolbar (reorder/edit/delete) alongside the
   row itself — one column gives that toolbar room to sit inline instead of
   wrapping awkwardly inside a half-width cell. Toggled by the .is-admin class
   js/portal.js sets on <body> once role is confirmed; purely a layout
   decision, unrelated to the access-control note on .padmin-bar in the HTML. */
.is-admin .rgrid{grid-template-columns:1fr}
/* Wrapper around each row (+ its admin toolbar, when present). display:flex
   here — not display:contents — is deliberate: it's what lets .res-admin sit
   beside .res as one visual unit instead of becoming its own separate grid
   cell and desyncing the two-column employee layout. */
.res-item{display:flex;align-items:stretch;gap:.5rem;min-width:0}
/* <button> and <a> in the same grid: reset the button's UA styling so the two
   are visually identical, and force text-align/font because buttons inherit
   neither. */
.res{display:flex;align-items:center;gap:.95rem;flex:1;min-width:0;text-align:left;
  font:inherit;color:inherit;cursor:pointer;text-decoration:none;
  background:var(--ink-2);border:1px solid var(--ink-3);border-radius:14px;
  padding:1rem 1.15rem;transition:border-color .2s,background .2s}
.res:hover{background:var(--ink-3);border-color:var(--purple-lift)}
.res__ic{flex-shrink:0;width:38px;height:38px;border-radius:10px;display:grid;place-items:center;
  background:rgba(87,60,129,.28);border:1px solid var(--ink-3)}
.res__ic svg{width:19px;height:19px;color:var(--purple-lift)}
.res__t{display:grid;gap:.15rem;min-width:0}
.res__n{font-family:var(--display);font-weight:700;font-size:.98rem;color:var(--bone)}
.res__d{font-size:.84rem;color:var(--bone-dim);line-height:1.4}
.res__go{margin-left:auto;flex-shrink:0;color:var(--grey);font-size:1.05rem;transition:color .2s,transform .2s}
.res:hover .res__go{color:var(--purple-lift);transform:translateX(3px)}
/* The two rows that genuinely go somewhere (tel:, mailto:) read as live. */
.res--live{border-color:var(--purple)}
.res--live .res__go{color:var(--purple-lift)}
/* A resource with no url and no file_path yet — a real, named folder Omar
   hasn't linked a document to. See the CHECK constraint comment in the
   migration for why this is a deliberate state, not a bug to hide. Still
   clickable (surfaces the toast below), just visibly not-yet-live. */
.res--unavailable{opacity:.55}
.res--unavailable:hover{background:var(--ink-2);border-color:var(--ink-3)}
.res--unavailable:hover .res__go{color:var(--grey);transform:none}

/* Per-row admin toolbar: reorder + edit + delete, plus an inline flag on any
   row that's still missing a link. */
.res-admin{flex-shrink:0;display:flex;align-items:center;gap:.35rem;flex-wrap:wrap}
.res-admin__flag{font-size:.72rem;font-weight:700;letter-spacing:.03em;text-transform:uppercase;
  color:var(--magenta-lift);white-space:nowrap;margin-right:.15rem}
.res-admin__btn{background:var(--ink-2);border:1px solid var(--ink-3);border-radius:9px;
  width:2.2rem;height:2.2rem;display:grid;place-items:center;color:var(--bone-dim);
  font:inherit;font-size:.85rem;cursor:pointer}
.res-admin__btn:hover{color:var(--bone);border-color:var(--purple-lift)}
.res-admin__btn:disabled{opacity:.4;cursor:not-allowed}
.res-admin__btn--text{width:auto;padding:0 .75rem;font-size:.78rem;font-weight:600}
.res-admin__btn--danger:hover{color:var(--magenta-lift);border-color:var(--magenta)}

/* Placeholder notice, shown on clicking any inert row. Sticky at the bottom of
   the viewport so it is visible no matter how far down the list the click was. */
.ptoast{position:sticky;bottom:16px;z-index:40;margin:2rem 0 0;
  padding:.85rem 1.1rem;background:var(--purple);color:#fff;border-radius:12px;
  font-size:.88rem;line-height:1.45;box-shadow:0 10px 30px rgba(0,0,0,.45)}

/* ---------- account / change password ----------
   Deliberately its own card, not another .rgrid row — this is a control, not
   a resource link, and grouping it with the folders above would bury the
   one section on the page that looks like it does something. Real form now:
   submits to supabase.auth.updateUser({ password }) in js/portal.js. The
   generic .gf input/select/textarea rules above (including the :disabled
   look) cover these fields too — nothing pwcard-specific needed for them. */
.pwcard{max-width:480px;background:var(--ink-2);border:1px solid var(--ink-3);
  border-radius:16px;padding:clamp(22px,3.4vw,32px)}
.pwcard__hd h4{font-family:var(--display);font-weight:700;font-size:1.1rem;color:var(--bone);margin:0}
.pwcard__note{margin:.5rem 0 0;font-size:.85rem;color:var(--bone-dim);line-height:1.5}
.pwcard__body{display:grid;gap:1rem;margin-top:1.5rem}
.pw-status{margin:0;padding:.6rem .8rem;border-radius:9px;font-size:.85rem;
  background:rgba(87,60,129,.18);border:1px solid var(--purple-lift);color:var(--bone)}
.pwcard__reqs{list-style:none;margin:0;padding:0;display:grid;gap:.45rem;
  font-size:.82rem;color:var(--bone-dim)}
.pwcard__reqs li{position:relative;padding-left:1.3rem}
.pwcard__reqs li::before{content:"";position:absolute;left:0;top:.5em;width:7px;height:7px;
  border-radius:50%;background:var(--ink-3);border:1px solid var(--grey)}
.pwcard__btn{width:100%;justify-content:center;margin-top:.2rem}
/* pointer-events:none so :hover's background/transform never fires — a
   disabled .btn-primary that still lifts on hover reads as clickable. */
.pwcard__btn[disabled]{opacity:.55;cursor:not-allowed;pointer-events:none}

/* ---------- footer ---------- */
.pfoot{border-top:1px solid var(--ink-3);padding:1.6rem 0}
.pfoot__in{display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;
  font-size:.82rem;color:var(--bone-dim)}

@media (max-width:820px){
  .rgrid{grid-template-columns:1fr}
}

/* ============ ROUND 2 ============
   Contacts became editable, a resource can now carry a PDF *and* a link, and
   the password block split in two. Everything below is additive — no round-1
   rule was changed. */

/* .psec-row and .psec-row .psec are already defined above (round 1) and are
   NOT redefined here — an earlier draft of this block restated .psec-row with
   justify-content:space-between, which quietly pushed the Rename / Delete
   buttons on every dynamic section heading out to the far right instead of
   sitting beside the title. Only the new button gets a rule. */
.psec-row__btn{flex-shrink:0;font-size:.8rem;padding:.45rem .85rem}

/* Optional-field furniture on the admin forms. */
.gf__opt{font-weight:400;color:var(--grey);text-transform:none;letter-spacing:0}
.gf__hint{margin:.35rem 0 0;font-size:.78rem;color:var(--grey);line-height:1.45}
.rf-remove{display:flex;align-items:center;gap:.5rem;margin-top:.55rem;
  font-size:.82rem;color:var(--bone-dim);cursor:pointer}
.rf-remove input{width:auto;margin:0;cursor:pointer}

/* A resource carrying BOTH a PDF and a link. The row itself stops being a
   control — with two destinations, a single click target would have to guess
   which one was meant — so it lays out as face-over-actions and the two
   buttons carry the click. Stays one column on narrow screens so a driver
   isn't picking between two 40%-width targets with a thumb. */
.res--multi{display:flex;flex-direction:column;align-items:stretch;gap:.85rem;cursor:default}
.res--multi:hover{background:var(--ink-2);border-color:var(--ink-3)}
.res__acts{display:flex;gap:.5rem;flex-wrap:wrap}
.res__act{flex:1 1 auto;min-width:9rem;text-align:center;text-decoration:none;
  background:var(--ink-3);border:1px solid transparent;border-radius:10px;
  padding:.6rem .9rem;color:var(--bone);font:inherit;font-size:.85rem;font-weight:600;
  cursor:pointer;transition:border-color .2s,background .2s}
.res__act:hover{border-color:var(--purple-lift);background:rgba(87,60,129,.32)}
.res__act:disabled{opacity:.55;cursor:progress}
.res__act--link{color:var(--purple-lift)}

/* "+ Link" / "+ PDF" quick-add buttons in the admin row toolbar. */
.res-admin__btn--add{color:var(--purple-lift);border-color:rgba(139,107,196,.45)}
.res-admin__btn--add:hover{color:var(--bone);background:rgba(87,60,129,.3)}

/* The shared-employee password card sits apart from the admin's own: it
   changes a credential other people depend on, so it reads as the heavier of
   the two rather than as a second copy of the same form. */
.pwcard--employee{margin-top:1.1rem;border-color:rgba(232,29,117,.35)}
.pwcard--employee .pwcard__hd h4{color:var(--magenta-lift)}

@media (max-width:560px){
  .res__act{min-width:0;flex:1 1 100%}
}

/* ============ ADMIN-ONLY: HIDDEN BY DEFAULT ============
   The JS sets hidden=true on every [data-admin-only] node for a non-admin,
   and that is still the mechanism. This rule is the floor underneath it: the
   default state of admin-only content is now NOT SHOWN, and it takes an
   explicit .is-admin on <body> — which only applyAdminVisibility(true) ever
   sets — to reveal it.

   Two things this buys. Admin controls can no longer flash on screen in the
   window between paint and the first getSession() resolving. And a driver
   cannot be shown an admin control by any single failure in the attribute
   path — a missed applyAdminVisibility call, a stale DOM restored from
   bfcache, an element added to the page without the hidden attribute. The
   attribute says "hide this now"; this says "this was never for you".

   Specificity 0,2,1 beats [hidden]'s 0,1,0, so it wins where they disagree —
   which is only ever in the direction of hiding more. */
body:not(.is-admin) [data-admin-only]{display:none!important}
