/* Same plain, functional look as the sibling modules. */
* { box-sizing: border-box; }
body { margin: 0; font: 15px/1.5 -apple-system, "Segoe UI", Helvetica, Arial,
       sans-serif; color: #1c2733; background: #f4f5f7; }

.topbar { display: flex; align-items: center; gap: 16px; padding: 10px 20px;
          background: #1c2733; color: #fff; flex-wrap: wrap; }
.brand { color: #fff; font-weight: 700; font-size: 18px;
         text-decoration: none; letter-spacing: 1px; }
.tagline { color: #9fb0c0; font-size: 13px; }
.mainnav { display: flex; gap: 14px; margin-left: 12px; }
.mainnav a { color: #d7e0e8; text-decoration: none; padding: 4px 2px; }
.mainnav a:hover { color: #fff; }
.signout { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.whoami { color: #9fb0c0; font-size: 13px; }

.wrap { max-width: none; margin: 24px auto; padding: 0 20px; }   /* the window, not a column: owner instruction 2026-09-11 */
h1 { font-size: 22px; margin: 8px 0 14px; }
h2 { font-size: 17px; margin: 26px 0 8px; }
small, .muted { color: #64748b; }

.flash { padding: 9px 13px; border-radius: 6px; margin-bottom: 12px; }
.flash-info { background: #e2efda; color: #2e5b2e; }
.flash-error { background: #fbe3e4; color: #8f2430; }

table { border-collapse: collapse; width: 100%; background: #fff;
        border: 1px solid #dde3ea; border-radius: 6px; overflow: hidden; }
th, td { text-align: left; padding: 7px 11px;
         border-bottom: 1px solid #eceff3; vertical-align: middle; }
th { background: #f0f2f5; font-size: 12px; text-transform: uppercase;
     letter-spacing: .4px; color: #4a5a6a; }
tr:last-child td { border-bottom: none; }
tr.over td { background: #fff4f2; }
tr.muted td { color: #94a3b2; }

.cards { display: grid; grid-template-columns: repeat(auto-fit,
         minmax(200px, 1fr)); gap: 14px; margin: 14px 0 8px; }
.card { display: block; background: #fff; border: 1px solid #dde3ea;
        border-radius: 8px; padding: 14px 16px; color: inherit;
        text-decoration: none; }
.card-warn { border-color: #e2a4a4; background: #fff8f7; }
.card .big { font-size: 30px; font-weight: 700; }

.panel { background: #fff; border: 1px solid #dde3ea; border-radius: 8px;
         padding: 14px 16px; margin-bottom: 18px; }
form { margin: 0; }
label { display: block; margin: 6px 0; }
label.inline { display: inline; margin: 0 6px; font-size: 13px; }
input, select { font: inherit; padding: 5px 8px; border: 1px solid #c4cdd6;
        border-radius: 5px; }
button { font: inherit; padding: 6px 14px; border: none; border-radius: 5px;
         background: #2456a4; color: #fff; cursor: pointer; }
button:hover { background: #1c4585; }
button.danger { background: #fff; color: #8f2430;
                border: 1px solid #d9a0a5; padding: 3px 10px; }
button.danger:hover { background: #fbe3e4; }
td form { display: inline-flex; gap: 6px; align-items: center; }

.pill { background: #8f2430; color: #fff; border-radius: 10px;
        font-size: 12px; padding: 1px 8px; vertical-align: middle; }

.login-card { max-width: 340px; margin: 10vh auto; background: #fff;
              border: 1px solid #dde3ea; border-radius: 8px;
              padding: 22px 26px; }
.login-card h1 { letter-spacing: 2px; }
.login-card input { width: 100%; }
.login-card button { width: 100%; margin-top: 12px; }

/* ------------------------------------------------------------- gantt */
.g-toolbar { display: flex; align-items: baseline; gap: 18px;
             flex-wrap: wrap; }
.g-nav a { margin-right: 10px; }
.g-zoom button { padding: 3px 10px; border-radius: 4px; background: #fff;
                color: #1c2733; border: 1px solid #c4cdd6; }
.g-zoom button.on { background: #1c2733; color: #fff; border-color: #1c2733; }
.g-layout { display: grid; grid-template-columns: 1fr 230px; gap: 16px;
            align-items: start; }
@media (max-width: 900px) { .g-layout { grid-template-columns: 1fr; } }

.gantt { display: grid; grid-template-columns: 230px 1fr;
         background: #fff; border: 1px solid #dde3ea; border-radius: 8px;
         overflow: hidden; }
.g-corner { padding: 6px 10px; font-size: 12px; color: #4a5a6a;
            border-bottom: 1px solid #dde3ea; background: #f0f2f5; }
.g-head { overflow: hidden; display: flex; border-bottom: 1px solid #dde3ea;
          background: #f0f2f5; }
.g-hcell { flex: 0 0 var(--dw); width: var(--dw); font-size: 10px;
           color: #4a5a6a; text-align: center; padding: 4px 0 2px;
           position: relative; min-height: 34px; overflow: visible; }
.g-day { display: inline-block; margin-top: 11px; }
.g-wk { position: absolute; top: 14px; left: 2px; font-size: 9px;
        white-space: nowrap; color: #4a5a6a; }
.g-hcell .g-month { position: absolute; top: 1px; left: 2px; font-size: 9px;
                    font-weight: 700; color: #1c2733; white-space: nowrap;
                    text-align: left; }
.g-hcell.g-sun { background: #e8ebef; color: #b6bfc9; }
.g-hcell.g-sat { background: #f6f7f9; }
.g-hcell.g-nwdcol { background: #fdeeee; }
.g-hcell.g-today { box-shadow: inset 0 -3px 0 #2456a4; }

.g-side { border-right: 1px solid #dde3ea; }
/* The wide view: one line per job, no rooms, just totals. The row's job
   colour rides in as --jc/--jt (tits.colors.job_style): a planned day is a
   light box with the crew in it, a clocked day a solid box with the people,
   and a trip is a bar along the bottom of the track that zooms the job's
   card when clicked. */
.g-wlabel { height: 44px; padding: 5px 10px 0 10px; font-size: 13px; font-weight: 600;
            white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
            border-top: 1px solid #f0f2f5; border-left: 5px solid var(--jc, #4a76c4); }
.g-wlabel a { color: inherit; text-decoration: none; }
.g-wlabel a:hover { text-decoration: underline; }
.g-wlabel small { display: block; font-size: 10px; font-weight: 400; color: #64748b; }
.g-wtrack { height: 44px; position: relative; border-top: 1px solid #f0f2f5;
            width: calc(var(--dw) * var(--ndays)); }
.g-wday { position: absolute; top: 5px; height: 22px; width: calc(var(--dw) - 2px);
          margin-left: 1px; border-radius: 3px; text-align: center; overflow: hidden;
          font-size: 10px; line-height: 22px; font-variant-numeric: tabular-nums; }
.g-wday.g-planned { background: var(--jt, #d6e4f5); color: #1c2733; font-weight: 600; }
.g-wday.g-worked { background: var(--jc, #2f6db5); color: #fff; font-weight: 700; }
.g-wtrip { position: absolute; bottom: 3px; height: 12px; border: 0; border-radius: 3px;
           background: var(--jc, #4a76c4); opacity: .55; color: #fff; font-size: 9px;
           line-height: 12px; padding: 0 6px; text-align: left; white-space: nowrap;
           overflow: hidden; cursor: pointer; font-family: inherit; }
.g-wtrip:hover { opacity: .9; }
.g-wtrip:focus-visible { outline: 2px solid #1c2733; }
/* the crew figure stays legible one zoom out; below that the boxes are
   too narrow for a digit and only their colour speaks */
.zoom-week .g-wday { font-size: 8px; }
.zoom-month .g-wday, .zoom-year .g-wday { font-size: 0; }
.zoom-month .g-wtrip, .zoom-year .g-wtrip { font-size: 0; padding: 0; }

/* One card per job: a header with the figures always showing and the trips
   as zoom buttons, then the job's own grid. */
.g-stack > * + * { margin-top: 18px; }
.g-card { border-left: 5px solid var(--jc, #4a76c4); border-radius: 8px; }
.g-cardhead { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 16px;
              padding: 6px 12px 8px; }
.g-cardhead h2 { margin: 0; font-size: 17px; color: var(--jc, #1c2733); }
.g-figs { font-size: 12px; color: #4a5a6a; }
.g-trips { display: flex; flex-wrap: wrap; gap: 6px; margin-left: auto; }
.g-trip { border: 1px solid var(--jc, #c4cdd6); background: #fff; color: #1c2733;
          border-radius: 5px; padding: 3px 9px; font-size: 12px; cursor: pointer;
          font-family: inherit; text-align: left; }
.g-trip small { display: block; font-size: 10px; color: #64748b; }
.g-trip.on { background: var(--jc, #1c2733); color: #fff; }
.g-trip.on small { color: rgba(255, 255, 255, .8); }
.g-tripband { position: absolute; top: 0; bottom: 0; background: var(--jt, #d6e4f5);
              opacity: .45; pointer-events: none; z-index: 0; }
/* A trip band is a DROP TARGET since 2026-09-24: dropping a room on it puts
   the room on that trip, which is the only thing that gives work dates. It
   therefore has to take pointer events, unlike the decoration it used to
   be -- but only while something is being dragged, so an ordinary click
   still reaches the bar underneath. */
.g-drag .g-tripband.g-drop { pointer-events: auto; }
.g-drag .g-tripband.g-drop.over { opacity: .8; outline: 2px dashed var(--jc, #2f6db5);
                                  outline-offset: -2px; }
.g-job .g-bar { background: var(--jc, #4a76c4); }
.g-job .g-bar.g-in_progress { box-shadow: inset 0 0 0 2px rgba(0, 0, 0, .28); }
.g-job .g-bar.g-complete { opacity: .5; }
.g-job .g-bar.g-pinnedbar { box-shadow: inset 0 0 0 2px #1c2733; }

/* The crew row at the top of a job's card: how many people are on the
   job each day. The same cells as the job's line in the wide view, kept
   here so the number is beside the rooms it is made of -- and it is what
   stays when the rooms are folded away (owner request 2026-09-15). */
.g-crewlabel { height: 36px; padding: 4px 10px 0; font-size: 12px; font-weight: 600;
               color: #4a5a6a; border-top: 1px solid #f0f2f5; white-space: nowrap;
               overflow: hidden; text-overflow: ellipsis; }
.g-crewlabel small { display: block; font-size: 10px; font-weight: 400; color: #64748b; }
.g-crewtrack { height: 36px; position: relative; border-top: 1px solid #f0f2f5;
               width: calc(var(--dw) * var(--ndays)); }
.g-crewcell { position: absolute; top: 7px; height: 22px; width: calc(var(--dw) - 2px);
              margin-left: 1px; border-radius: 3px; text-align: center; overflow: hidden;
              font-size: 11px; line-height: 22px; font-variant-numeric: tabular-nums; }
.g-crewcell.g-planned { background: var(--jt, #d6e4f5); color: #1c2733; font-weight: 700; }
.g-crewcell.g-worked { background: var(--jc, #2f6db5); color: #fff; font-weight: 700; }
.zoom-week .g-crewcell { font-size: 8px; }
.zoom-month .g-crewcell, .zoom-year .g-crewcell { font-size: 0; }

/* Folding a card: the rooms go, the header's figures and the crew row
   stay, and the choice is remembered per job in this browser. */
.g-fold { border: 1px solid #c4cdd6; background: #fff; color: #1c2733; border-radius: 4px;
          width: 24px; height: 24px; line-height: 20px; padding: 0; cursor: pointer;
          font-size: 13px; align-self: center; }
.g-card.g-folded .g-fold { transform: rotate(-90deg); }
.g-card.g-folded .g-roomrow { display: none; }
.g-foldall button { padding: 3px 10px; border-radius: 4px; background: #fff;
                    color: #1c2733; border: 1px solid #c4cdd6; }

/* The rooms of a card are grouped under the trip that does them (2026-09-24).
   The heading row on the side has a matching spacer on the track side, so
   the two columns stay in step. */
.g-triplabel { height: 28px; padding: 5px 10px 0; font-size: 12px; font-weight: 700;
               color: #1c2733; background: #f4f6f9;
               border-top: 1px solid #dde3ea; white-space: nowrap;
               overflow: hidden; text-overflow: ellipsis; }
.g-triplabel small { display: block; font-size: 10px; font-weight: 400;
                     color: #64748b; margin-top: -2px; }
.g-tripnone { background: #fdf3e3; color: #8a5a12; }
.g-tripgap { height: 28px; border-top: 1px solid #dde3ea; background: #f4f6f9; }
.g-card.g-folded .g-triplabel, .g-card.g-folded .g-tripgap { display: none; }

.g-rowlabel { height: 50px; padding: 4px 10px; font-size: 14px;
              white-space: nowrap; overflow: hidden;
              text-overflow: ellipsis; border-top: 1px solid #f0f2f5; }
.g-rowlabel small { display: block; font-size: 10px; color: #64748b;
                    margin-top: -3px; }
.g-rowlabel a { color: inherit; text-decoration: none; }
.g-rowlabel a:hover { text-decoration: underline; }
.g-loadlabel { height: 68px; padding: 22px 10px 0; font-size: 11px;
               color: #4a5a6a; border-top: 2px solid #dde3ea; }
.g-loadlabel small { display: block; font-size: 10px; color: #64748b; }

.g-body { overflow-x: auto; position: relative; }
.g-track { height: 50px; position: relative; border-top: 1px solid #f0f2f5;
           width: calc(var(--dw) * var(--ndays)); }
.g-loadtrack { height: 68px; position: relative; border-top: 2px solid #dde3ea;
               width: calc(var(--dw) * var(--ndays)); }
.g-col { position: absolute; top: 0; bottom: 0; width: var(--dw);
         pointer-events: none; z-index: 0; }
.g-colsun { background: rgba(28, 39, 51, 0.07); }
.g-colnwd { background: rgba(199, 66, 66, 0.08); }
.g-todayline { position: absolute; top: 0; bottom: 0; width: 2px;
               background: #2456a4; z-index: 1; pointer-events: none; }

.g-bar { position: absolute; top: 6px; height: 28px; border-radius: 5px;
         background: #4a76c4; color: #fff; font-size: 12px;
         line-height: 28px; padding: 0 8px; white-space: nowrap;
         overflow: hidden; text-overflow: ellipsis; cursor: grab;
         user-select: none; z-index: 2; touch-action: none; }
.g-bar:active { cursor: grabbing; }
.g-in_progress { background: #2b8a5b; }
.g-complete { background: #9aa8b6; }
.g-pinnedbar { box-shadow: inset 0 0 0 2px #1c2733; }
.g-pin { margin-left: 4px; }
.g-clip-l { border-top-left-radius: 0; border-bottom-left-radius: 0;
            border-left: 3px dotted #fff; }
.g-clip-r { border-top-right-radius: 0; border-bottom-right-radius: 0;
            border-right: 3px dotted #fff; }

.g-loadcell { position: absolute; bottom: 20px; width: calc(var(--dw) - 2px);
              margin-left: 1px; background: #9db8dd; border-radius: 2px; }
.g-loadcell.g-over { background: #c74242; }

/* The figures under the bars. The bars are scaled against capacity and
   capped, so on their own they say "busy" and "too busy" and never say how
   many — which is the number you actually schedule against. */
.g-loadnum { position: absolute; bottom: 4px; width: var(--dw);
             text-align: center; font-size: 10px; line-height: 12px;
             color: #4a5a6a; pointer-events: none; }
.g-loadnum.g-over { color: #a3232c; font-weight: 700; }

/* Deployable headcount, drawn where the bars cross it. The bar heights are
   capped, so without this the difference between "one over" and "ten over"
   is invisible — both bars are simply full height. */
.g-loadcap { position: absolute; bottom: 56px; left: 0; z-index: 0;
             width: calc(var(--dw) * var(--ndays));
             border-top: 1px dashed #94a3b8; }

.g-backlog { background: #fff; border: 1px solid #dde3ea; border-radius: 8px;
             padding: 12px 14px; }
.g-backlog h2 { margin: 0 0 10px; }
.g-bl { border: 1px solid #dde3ea; border-radius: 6px; padding: 6px 10px;
        margin-bottom: 8px; cursor: grab; background: #f7f8fa; }
.g-bl:active { cursor: grabbing; }
.g-bl a { text-decoration: none; color: inherit; font-weight: 600; }
.g-bl small { display: block; color: #64748b; }
/* Work that has DATES and no trip behind it: the legacy rows migration 022
   could not place, and the state the whole change exists to end. Badged, so
   it is the first thing somebody deals with. */
.g-blplaced { border-color: #e0b356; background: #fdf3e3; }

.detail-grid { display: grid; grid-template-columns: repeat(auto-fit,
               minmax(280px, 1fr)); gap: 14px; align-items: start; }
.detail-grid .panel { margin-bottom: 0; }
.detail-grid form.panel label input { width: 100%; }
.fields { display: flex; gap: 14px; flex-wrap: wrap; align-items: end; }


/* ------------------------------------------------- gantt zoom + layout */
.wrap.wide { max-width: none; margin: 18px 22px; }

/* what each zoom density shows: day numbers, weekly markers, or months */
.zoom-day .g-wk { display: none; }
.zoom-week .g-day, .zoom-month .g-day, .zoom-year .g-day { display: none; }
.zoom-month .g-wk, .zoom-year .g-wk { display: none; }
.zoom-month .g-bar span, .zoom-year .g-bar span { display: none; }
.zoom-month .g-bar, .zoom-year .g-bar { padding: 0; }
.zoom-week .g-loadnum, .zoom-month .g-loadnum,
.zoom-year .g-loadnum { display: none; }
.zoom-week .g-aday span, .zoom-month .g-aday span,
.zoom-year .g-aday span { display: none; }
.zoom-week .g-aday, .zoom-month .g-aday, .zoom-year .g-aday {
  height: 5px; top: 33px; }
.zoom-year .g-hcell.g-sat, .zoom-year .g-hcell.g-sun { background: none; }

/* pan empty grid space by dragging */
.g-track, .g-wtrack, .g-loadtrack { cursor: grab; }
.g-body.g-panning, .g-body.g-panning .g-track { cursor: grabbing; }

/* --------------------------------------------- progress: bars and boxes */
/* A percent box the operator has not filled in shows the INFERRED figure as
   a placeholder, greyed and italic, so a guess never looks like a report. */
.pct-cell input { width: 62px; text-align: right; }
.pct-cell input.inferred::placeholder { color: #94a3b8; font-style: italic; }

.bar { background: #eef1f5; border-radius: 3px; height: 8px;
       overflow: hidden; margin: 2px 0; min-width: 60px; }
.bar span { display: block; height: 100%; background: #2b8a5b;
            border-radius: 3px; }

table.installs td.w, table.installs th.w { width: 22%; }
table.installs .totals td { font-weight: 700; border-top: 2px solid #dde3ea; }

/* The burn-rate note. It is a signal, not an alarm — .pill is the alarm —
   and it is only bad news in one of its two directions, so it is coloured
   by which. */
.forecast { border-radius: 8px; padding: 10px 14px; font-size: 13px;
            border: 1px solid; margin: 0 0 14px; }
.forecast-over  { background: #fff8ef; border-color: #e3bd8a; color: #6b4415; }
.forecast-under { background: #f2f9f4; border-color: #a8ccb4; color: #235437; }

/* Days somebody actually worked the room, drawn under the planned bar. The
   plan says where work was PUT; these say where it WENT. */
/* A worked day carries its man-days. The figure is the point of the strip —
   the bar above it says a room was open, this says how much of the crew was
   in it. Hours stay in the tooltip: man-days are what gets added up. */
.g-aday { position: absolute; top: 33px; height: 14px; z-index: 1;
          width: calc(var(--dw) - 2px); margin-left: 1px;
          background: #d98324; border-radius: 2px;
          font-family: inherit; font-size: 9.5px; line-height: 14px;
          color: #fff; text-align: center; overflow: hidden; }
.g-aday span { display: block; }
.g-akey { display: inline-block; width: 14px; height: 8px; margin: 0 2px 0;
          background: #d98324; border-radius: 2px; }

/* Behind today the load strip is what was worked, not what was planned. Amber
   ties it to the worked-day cells above; it is never flagged red, because an
   overloaded week in March is not something anybody can still act on. */
.g-loadcell.g-actual { background: #d98324; }
.g-loadnum.g-actualnum { color: #8a5312; }

/* ------------------------------------------------------- mobilizations */
table.trips input[type="text"], table.trips input:not([type]) { width: 100%; }
table.trips td { padding: 5px 10px 5px 0; }
table.trips tr.newtrip td { border-bottom: 0; background: #f7f8fa; }
table.trips th { white-space: nowrap; }

/* The split picker on a task mapping: a scrollable room list with a weight
   beside each room, so a takeoff with a hundred rooms stays one form. */
details.split { display: inline-block; vertical-align: top; }
details.split summary { cursor: pointer; font-size: 13px; color: #64748b; }
details.split p { max-width: 32em; margin: 4px 0; }
.split-rooms { max-height: 14em; overflow-y: auto; border: 1px solid #dde3ea;
  border-radius: 6px; padding: 4px 8px; background: #fff; }
.split-rooms label { display: flex; gap: 6px; align-items: center;
  font-size: 13px; white-space: nowrap; }
.split-rooms label input[type=number] { width: 3.5em; margin-left: auto; }

/* The rooms panel of a trip (2026-09-15): the picker, the recommendation
   beside the days box, and the laid-out rows with a tag on a room that
   runs past the trip's days. */
.trip-rooms .split-rooms { max-height: 18em; }
.trip-rooms .split-rooms label small { margin-left: auto; white-space: nowrap; }
.trip-days { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; }
.trip-days input[type=number] { width: 4.5em; }
.trip-rooms .split-rooms label.on-other { opacity: .5; }
.trip-rooms .split-rooms label.on-other:hover { opacity: .85; }
