/* The Team section.
 *
 * Layout only, plus the few pieces app.css does not already own. The tokens,
 * .card, .btn, .field, .in, .muted, .err, .sheet, .scrim and .toast all come
 * from app.css, so this page cannot drift from the map the reps use.
 *
 * Phone first, like the rest of the portal. Steve reads this on a laptop most
 * days and on a phone in the truck the rest of the time, so the narrow layout
 * is the real one and the wide layout is the variant.
 */

/* app.css locks the map page to the viewport. This page is a document and
   scrolls, so that lock has to come off. */
html, body.fc-team { height: auto; min-height: 100%; overflow: visible; }
body.fc-team { background: var(--bg-soft); }

/* Two local inks, and they exist for one reason each, measured rather than
   guessed. The brand --red on its own --red-tint is 4.44:1, under AA for
   normal text, so it cannot be the ink on the warning it belongs to. --amber
   on --amber-bg does clear at 5.06:1, and the darker note ink is used anyway
   because these blocks carry small type. Same hues, darkened until they are
   comfortable rather than borderline. */
body.fc-team {
  --warn-ink: #b42318;          /* 6.05:1 on --red-tint, 6.40:1 on the blocked card */
  --warn-line: rgba(180, 35, 24, 0.30);
  --note-ink: #8a4708;          /* 6.56:1 on --amber-bg */
}

.tm {
  max-width: 1180px; margin: 0 auto;
  /* The shell measures itself into these, so the page clears the bar whether
     it landed on the top or the bottom, safe area included. Guessing that
     number is how the map ended up with a card sitting inside its own dock. */
  padding: calc(var(--fshell-top-h, 0px) + 14px) 16px calc(var(--fshell-bottom-h, 0px) + 28px);
}

/* ----------------------------------------------------------------- head */
.tm-head { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 12px; margin-bottom: 14px; }
.tm-head img { height: 38px; width: auto; flex: none; }
/* A real basis, not a bare flex: 1. With basis 0 and min-width 0 the title can
   shrink for ever, so on a phone it never wraps, it collapses to a sliver and
   sets one word per line beside the name chip. 240px is roughly where the two
   stop fitting side by side, so below that the chip drops to its own row. */
.tm-head-t { min-width: 0; flex: 1 1 240px; }
.tm-head h1 { font-size: 21px; }
.tm-head .sub { color: var(--mute); font-size: 13.5px; margin-top: 2px; }
/* 52px tall so the Sign out button inside it can be a real 44px target. */
.tm-who {
  flex: none; display: inline-flex; align-items: center; gap: 6px; min-height: 52px; padding: 0 4px 0 12px;
  margin-left: auto; max-width: 100%; min-width: 0;
  border-radius: 999px; background: #fff; border: 1px solid var(--line); font-size: 12.5px; color: var(--ink-2);
}
.tm-who b { font-family: var(--head); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.tm-who button {
  border: 0; background: transparent; color: var(--blue-deep); font-family: var(--head); font-weight: 700;
  font-size: 12.5px; cursor: pointer; padding: 0 12px; min-height: 44px; border-radius: 999px;
}
.tm-who button:hover { background: var(--blue-tint); }

.tm-load { color: var(--mute); font-size: 14px; padding: 24px 2px; }

/* ----------------------------------------------------------------- grid */
.tm-grid { display: grid; gap: 14px; grid-template-columns: minmax(0, 1fr); }
.tm-grid > .card { padding: 16px; min-width: 0; }
.tm-step { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 10px; margin-bottom: 12px; }
.tm-step h2 { font-size: 16px; }
.tm-count { color: var(--mute); font-size: 13px; }
/* app.css's .btn.small is 38px tall, under the 44px this page holds itself
   to, so the header button is the full primitive with a tighter box rather
   than the small variant. */
.tm-step .btn { margin-left: auto; padding: 10px 14px; font-size: 14px; }
/* Two buttons in one header. Only the FIRST takes the auto margin, or the free
   space is shared out between them and they end up at opposite ends of the row
   looking unrelated, when they are the same job from two directions. */
.tm-step .btn + .btn { margin-left: 8px; }

/* -------------------------------------------------------- out of area */
/* Loud on purpose. Nobody carrying this is invisible everywhere else in the
   product: the booking still goes through, it just lands on nobody. */
.tm-banner {
  display: flex; align-items: flex-start; gap: 10px;
  border-radius: 12px; padding: 12px 13px; font-size: 14px; line-height: 1.45;
}
.tm-banner svg { width: 20px; height: 20px; flex: none; margin-top: 1px; }
.tm-banner b { font-family: var(--head); font-weight: 800; display: block; font-size: 14.5px; margin-bottom: 2px; }
.tm-banner .grow { min-width: 0; }
.tm-banner.bad { background: var(--red-tint); border: 1px solid var(--warn-line); color: var(--warn-ink); }
.tm-banner.good { background: var(--blue-tint); border: 1px solid var(--blue-line); color: #0b4f96; }
.tm-ooa .muted { margin-top: 10px; }
.tm-evidence { display: block; margin-top: 6px; }
.tm-ooa .tm-note { margin-top: 10px; }

/* Who takes them, as the same coloured identity they carry on the map and in
   the roster, so the answer to "who" is read rather than searched for. They
   sit inside the banner, which is why the ink is inherited rather than set:
   the banner is blue in one state and red in the other and the chip has to be
   legible on both. */
.tm-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.tm-chip {
  display: inline-flex; align-items: center; gap: 6px; min-height: 26px; padding: 0 9px;
  border-radius: 999px; background: rgba(255, 255, 255, 0.82); border: 1px solid currentColor;
  font-family: var(--head); font-weight: 700; font-size: 12.5px; color: inherit;
}
/* .tm-dot is sized and nudged for the top of a roster row. In a chip it is
   vertically centred already, so both are reset here rather than the shared
   dot being loosened for everybody. */
.tm-chip .tm-dot { width: 10px; height: 10px; border-radius: 3px; margin-top: 0; }

/* --------------------------------------------------------- the switch */
/* The day switch on /hours is the control Steve already knows, so this is that
   control: same 62x44 hit box, same 50x30 track, same 24px knob, same travel.
   One control that behaves two ways in one product is two controls. */
.tm-swwrap { min-width: 0; }
.tm-sw {
  display: flex; align-items: center; gap: 10px; min-height: 52px; padding: 5px 12px 5px 4px;
  border: 1px solid var(--line); border-radius: 12px; background: var(--bg-soft);
}
.tm-sw.on { background: var(--blue-tint); border-color: var(--blue-line); }
/* On, with nothing behind it. The switch and the warning under it are drawn as
   one block, corners and all, because they are one fact and two separate red
   things is how somebody reads neither. */
.tm-sw.warn {
  background: var(--red-tint); border-color: var(--warn-line);
  border-bottom-left-radius: 0; border-bottom-right-radius: 0; border-bottom: 0;
}
.tm-stop.joined { border-top-left-radius: 0; border-top-right-radius: 0; margin-top: 0; }
.tm-switch {
  width: 62px; height: 44px; padding: 0; border: 0; background: transparent; flex: none;
  cursor: pointer; display: grid; place-items: center; border-radius: 12px;
}
.tm-switch i {
  display: block; width: 50px; height: 30px; border-radius: 999px; position: relative;
  /* Darker than the /hours track, and the reason is measured through the same
     canvas the contrast sweep uses, not worked out by hand: a switch is a
     control, so its off state needs 3:1 against the ground it sits on or it is
     not visibly a switch at all. #c4ccd8, which /hours uses, comes out at
     1.62:1 on white and 1.53:1 on this row's own ground. This one is 4.61:1 and
     4.36:1 on the same two. Worth fixing in hours.css as well. */
  background: #6a7688; transition: background 140ms;
}
.tm-switch i::after {
  content: ''; position: absolute; top: 3px; left: 3px; width: 24px; height: 24px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 3px rgba(16, 24, 40, 0.3); transition: transform 140ms;
}
.tm-switch[aria-checked="true"] i { background: var(--blue-deep); }
.tm-switch[aria-checked="true"] i::after { transform: translateX(20px); }
.tm-switch:focus-visible { outline: 3px solid var(--blue); outline-offset: 1px; }
.tm-sw-t { min-width: 0; flex: 1; font-size: 13.5px; line-height: 1.35; }
.tm-sw-t b { font-family: var(--head); font-weight: 700; display: block; color: var(--ink); }
.tm-sw-say { display: block; color: var(--ink-2); font-size: 12.5px; }
.tm-sw-err { color: var(--warn-ink); font-size: 12.5px; line-height: 1.45; margin-top: 6px; }

/* --------------------------------------------------------------- roster */
.tm-reps { display: grid; gap: 10px; }
.tm-rep {
  border: 1px solid var(--line); border-radius: 14px; padding: 12px; background: #fff;
  display: flex; flex-direction: column; gap: 10px; min-width: 0;
}
/* A rep who cannot receive a booking is not a styling nuance. The card itself
   changes so the row is findable by scrolling past it fast. */
.tm-rep.blocked { border-color: var(--warn-line); background: #fffbfb; }
.tm-rep-top { display: flex; align-items: flex-start; gap: 10px; min-width: 0; }
/* The same colour the rep paints with on the map, so the roster and the map
   are one identity. The inset ring keeps the lighter colours off white. */
.tm-dot { width: 14px; height: 14px; border-radius: 5px; flex: none; margin-top: 3px; box-shadow: inset 0 0 0 1px rgba(16, 24, 40, 0.22); }
.tm-id { flex: 1; min-width: 0; }
.tm-id b { font-family: var(--head); font-weight: 800; font-size: 15.5px; display: block; letter-spacing: -0.01em; }
.tm-id span { display: block; color: #4a5567; font-size: 13px; margin-top: 2px; word-break: break-word; }
.tm-facts { display: flex; flex-wrap: wrap; gap: 6px; }
.tm-fact {
  display: inline-flex; align-items: center; gap: 6px; min-height: 28px; padding: 0 10px;
  border-radius: 999px; background: var(--bg-soft); border: 1px solid var(--line);
  font-size: 12.5px; color: #3d4859;
}
.tm-fact b { font-family: var(--head); font-weight: 700; color: var(--ink); }
.tm-hours { font-size: 13px; color: var(--ink-2); line-height: 1.5; }
.tm-hours i { font-style: normal; font-family: var(--head); font-weight: 700; color: var(--ink); }
.tm-note {
  background: var(--amber-bg); border: 1px solid rgba(181, 71, 8, 0.28); color: var(--note-ink);
  border-radius: 10px; padding: 9px 11px; font-size: 12.5px; line-height: 1.45;
}
/* The two silent failures. Plain, loud, and they say the consequence rather
   than the condition, because "no hours" means nothing to Steve and "can never
   be sent an estimate" means everything. */
.tm-stop {
  display: flex; align-items: flex-start; gap: 9px;
  background: var(--red-tint); border: 1px solid var(--warn-line); color: var(--warn-ink);
  border-radius: 10px; padding: 10px 11px; font-size: 13px; line-height: 1.45;
}
.tm-stop + .tm-stop { margin-top: 8px; }
.tm-stop svg { width: 18px; height: 18px; flex: none; margin-top: 1px; }
.tm-stop b { font-family: var(--head); font-weight: 800; display: block; margin-bottom: 1px; }
.tm-stop .grow { min-width: 0; }
.tm-rep-go { display: flex; gap: 8px; align-items: center; }
.tm-rep-go .spacer { flex: 1; }
.tm-foot { margin-top: 14px; }
.tm-foot-go { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.tm-foot-go .btn { flex: 1 1 200px; }

/* app.css sizes the passcode toggle at 34px, which is under the 44px this
   page holds itself to. Scoped here rather than changed in app.css because
   app.css is the map's and the booker's too, and one page is not the place to
   move a shared primitive. The same 34px is on /book and /calendar and it
   belongs in app.css, not here. It fits inside the 48px field with room. */
body.fc-team .pw-toggle { min-height: 44px; right: 3px; }

/* The sheet's close button. app.css has a .close at 32px square, which is a
   real primitive with real users, so this page brings its own 44px one rather
   than restyling theirs out from under the map. */
.tm-x {
  margin-left: auto; width: 44px; height: 44px; border: 0; background: var(--bg-soft);
  border-radius: 11px; cursor: pointer; color: #4a5567; font-size: 20px; line-height: 1; flex: none;
}
.tm-x:hover { background: var(--line); color: var(--ink); }

/* A plain text button. Used where a link would be wrong because it does not
   navigate, and it still has to be a 44px target. */
.tm-link {
  border: 0; background: transparent; color: var(--blue-deep); cursor: pointer;
  font-family: var(--head); font-weight: 700; font-size: 13.5px;
  min-height: 44px; padding: 0 10px; border-radius: 10px; margin-top: 8px;
}
.tm-link:hover { background: var(--blue-tint); }

/* --------------------------------------------------------------- denied */
/* Below the shell's z index rather than above it, unlike the sign in gate. A
   rep who lands here is not blocked from the portal, they are on the wrong
   tab, so the tab bar has to stay tappable and the page pads around it. */
#denied { z-index: 30; }
#denied .gate-in {
  padding-top: calc(var(--safe-t) + var(--fshell-top-h, 0px) + 20px);
  padding-bottom: calc(var(--safe-b) + var(--fshell-bottom-h, 0px) + 24px);
}
.tm-denied-h { font-size: 18px; }
.tm-denied-p { margin-top: 8px; font-size: 14px; }
.tm-denied-go { display: flex; gap: 8px; margin-top: 14px; flex-wrap: wrap; }
.tm-denied-go .btn { flex: 1 1 150px; }

/* ------------------------------------------------- the Housecall Pro team
   The picker. Their whole team is in here, crew and office included, so the
   list is a directory to search rather than a list of suggestions: nothing is
   highlighted, nothing is ordered by "you should probably add this one", and
   the people already on the roster keep their place in it rather than being
   swept to the bottom where Steve would look for them and not find them. */
.tm-emps { display: grid; gap: 8px; max-height: 44vh; overflow-y: auto; padding: 2px; }
.tm-emp {
  display: flex; align-items: center; gap: 10px; min-width: 0;
  border: 1px solid var(--line); border-radius: 12px; padding: 10px 11px; background: #fff;
}
/* Already on the roster. Quieter, not struck through: they are not an error,
   they are simply not a thing to press. */
.tm-emp.on { background: var(--bg-soft); }
.tm-emp-id { flex: 1; min-width: 0; }
.tm-emp-id b { font-family: var(--head); font-weight: 700; font-size: 14.5px; display: block; }
.tm-emp-id span { display: block; color: #4a5567; font-size: 12.5px; margin-top: 1px; word-break: break-word; }
.tm-emp .btn { flex: none; padding: 10px 16px; font-size: 14px; }
.tm-emp-on {
  flex: none; display: inline-flex; align-items: center; min-height: 28px; padding: 0 10px;
  border-radius: 999px; background: var(--blue-tint); border: 1px solid var(--blue-line);
  color: #0b4f96; font-family: var(--head); font-weight: 700; font-size: 12px;
}
.tm-emp-none { color: var(--mute); font-size: 13px; padding: 10px 2px; }
/* The way out for somebody genuinely not in Housecall Pro yet. Deliberately
   below the list and deliberately plain: it is the exception, and an office
   must not be stopped by a record nobody has created over there. */
.tm-alt { border-top: 1px solid var(--line); margin-top: 14px; padding-top: 6px; }

/* --------------------------------------------------------- the mirror plan */
/* What a match WOULD do, shown before anything is written. One row per rep,
   one line per field, in the rep's own words rather than as a field name. */
.tm-plan { display: grid; gap: 8px; }
.tm-plan-rep {
  border: 1px solid var(--line); border-radius: 12px; padding: 10px 11px; background: #fff; min-width: 0;
}
.tm-plan-rep b { font-family: var(--head); font-weight: 700; font-size: 14.5px; display: block; }
.tm-plan-rep ul { list-style: none; margin: 6px 0 0; padding: 0; }
.tm-plan-rep li { font-size: 13px; line-height: 1.5; color: var(--ink-2); }
/* The change that can lock somebody out of the portal reads differently from
   the ones that cannot. */
.tm-plan-rep li.login { color: var(--warn-ink); font-weight: 700; }
.tm-plan-rep .was { color: var(--mute); }
.tm-plan-count { font-size: 13px; color: var(--mute); }

/* ---------------------------------------------------------------- sheet */
.tm-sheet-p { font-size: 13.5px; line-height: 1.5; color: var(--ink-2); }
.tm-sheet-p + .field { margin-top: 12px; }
.tm-sheet-go { display: flex; gap: 8px; margin-top: 16px; flex-wrap: wrap; }
.tm-sheet-go .btn { flex: 1 1 150px; }
.sheet-body .tm-stop { margin-top: 12px; }

/* ---------------------------------------------------------------- toast */
body.fc-team #toast {
  position: fixed; left: 50%; transform: translateX(-50%); z-index: 50; max-width: calc(100% - 32px);
  bottom: calc(var(--fshell-bottom-h, 0px) + 14px);
}

/* -------------------------------------------------------------- desktop */
@media (min-width: 760px) {
  .tm-head h1 { font-size: 24px; }
  /* Cards side by side would put the roster in a column too narrow to read a
     warning in. The out of area card stays full width above it and the reps
     become a grid inside their own card, which is where the extra width
     helps. */
  .tm-reps { grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); align-items: start; }
  .tm-grid > .card { padding: 20px; }
}
@media (min-width: 900px) {
  body.fc-team #toast { left: auto; right: 24px; transform: none; bottom: 24px; }
}

@media (prefers-reduced-motion: reduce) {
  .tm *, .tm *::before, .tm *::after, .tm-switch i, .tm-switch i::after {
    transition-duration: 0.01ms !important; animation-duration: 0.01ms !important;
  }
}

/* --- phone header ---------------------------------------------------------
   Below 600px the logo, the title and the name chip cannot share a row without
   the title losing. Put the logo and the chip together on the top row and give
   the title its own full width row underneath, which also lines its left edge
   up with the cards below it instead of indenting it past the logo. */
@media (max-width: 600px) {
  .tm-head { align-items: center; }
  .tm-head img { order: 1; }
  .tm-who { order: 2; margin-left: auto; }
  .tm-head-t { order: 3; flex: 1 1 100%; }
}
