/* ============================================================================
   screens/attendance.css - check in, and the record of every day

   Owns four things and nothing else:
     1. the Today card, which is the largest object on any screen in this app
        because it holds the one control the screen exists for;
     2. the capture dialog: the viewfinder, the shutter and the still;
     3. the team panel a supervisor reads in one glance;
     4. the record, as thumbnails and rows on a phone and as a table above the
        shell breakpoint.

   Everything else - cards, panels, badges, pills, buttons, avatars, the empty
   state, the skeletons, the filter bar - is the shared vocabulary from
   components.css and mobile.css. This file adds no colour of its own: every
   value is a token from tokens.css, and no rule here raises its priority.

   Class names are attendance-only (.att*), so nothing here can leak onto
   another screen even though the file is linked globally from index.html.

   THE 56px FLOOR IS THE POINT OF THE WHOLE FILE.
   Contract section 4.5 puts the general touch floor at 44px. .att-big is 56
   and .att-shutter is 60, because both are pressed one handed, standing up,
   often while holding something else. The two buttons in this app that people
   press in a hurry are the two biggest buttons in this app.

   Motion. attendance.js rebuilds every slot on every render - a fetch landing,
   a filter change, a check in - so every entrance here is an animation with
   `backwards` fill that starts the moment the node exists; nothing waits for a
   class JS might not add. The keyframes are the shared rise-in and fade-in from
   base.css, ordered by the `--i` property attendance.js writes on each item.
   Every duration is a --t-* token, so base.css's reduced-motion block collapses
   all of it by overriding the tokens alone.
   ========================================================================== */


/* ---------------------------------------------------------------------------
   1. Screen skeleton

   The desktop scroller is a plain column: three blocks, one gap, in the order
   the person needs them. No height arithmetic anywhere - the Today card is as
   tall as its own content and the record takes whatever is left.
   --------------------------------------------------------------------------- */

.att{
  display: flex;
  flex-direction: column;
  gap: var(--s-6);
}

.att-sec{
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  min-width: 0;
}

.att-filters{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  min-width: 0;
}

.att-chips{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  min-width: 0;
}

.att-chips:empty{
  display: none;
}

/* The filter label inside the chip, so "Range" reads as the key and the value
   reads as the value without either needing a colour of its own. */
.att-chip-k{
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  font-size: 10px;
  color: var(--muted);
}

.att-chip .ui-x{
  width: 12px;
  height: 12px;
}

.att-summary{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--s-3);
  min-width: 0;
}

.att-count{
  margin: 0;
  font-size: 12.5px;
  color: var(--muted);
}

.att-stage{
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  min-width: 0;
}

.att-stats:empty{
  display: none;
}

/* One figure per column while there is room, one per row when there is not.
   auto-fit rather than a media query: the strip sits in two different columns
   (the desktop scroller and the narrower mobile body) and should answer the
   space it actually has. */
.att-stats{
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--s-3);
  min-width: 0;
}

.att-pager{
  display: flex;
  justify-content: center;
  padding-top: var(--s-2);
}


/* ---------------------------------------------------------------------------
   2. The Today card

   The hero of the screen. It carries more padding than any other card in the
   app and a display-face date, because on a phone it is the first thing under
   the header and it has to read as "this is about you, now".
   --------------------------------------------------------------------------- */

.att-today{
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  padding: var(--s-5);
  animation: rise-in var(--t-base) backwards;
  transition: border-color var(--t-base), box-shadow var(--t-base);
}

.att-today--busy{
  padding: var(--s-4);
}

.att-today-h{
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-3);
  min-width: 0;
}

.att-today-when{
  min-width: 0;
}

.att-today-date{
  display: block;
  font-family: var(--f-disp);
  font-size: 20px;
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.2;
  color: var(--ink);
}

.att-today-shift{
  margin: var(--s-1) 0 0;
}

/* The facts of the day: the roster and the check in, never more than two since
   check out was retired. The auto-fit lays them side by side on a desktop card;
   the phone rule below holds them at two columns. */
.att-marks{
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(128px, 1fr));
  gap: var(--s-3) var(--s-4);
  margin: 0;
  padding: var(--s-4) 0;
  border-top: 1px solid var(--gray-200);
  border-bottom: 1px solid var(--gray-200);
}

.att-mark{
  min-width: 0;
}

.att-mark dt{
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--gray-600);
}

.att-mark dd{
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  margin: var(--s-1) 0 0;
}

.att-mark dd b{
  font-family: var(--f-mono);
  font-size: 17px;
  font-weight: 600;
  line-height: 1.2;
  color: var(--ink);
}

/* "Not started yet" is a sentence, not a time: the text face, not mono. */
.att-mark dd b.att-mark-word{
  font-family: var(--f-ui);
}

/* A verdict badge sitting beside a time. Inline, exactly as wide as its label:
   a chip that stretches to the card width stops looking like a chip. */
.att-late{
  flex: none;
}

.att-hint{
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin: 0;
  font-size: 12.5px;
  color: var(--muted);
  animation: fade-in var(--t-base) both;
}

.att-hint .ic{
  flex: none;
  width: 16px;
  height: 16px;
}

.att-hint--late{
  color: var(--gold-700);
}

.att-today-act{
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}

/* THE BUTTON. 56px is a floor, not a height: a label that wraps on a narrow
   phone grows the button rather than clipping itself. */
.att-big{
  min-height: 56px;
  padding: var(--s-3) var(--s-5);
  font-size: 15px;
  gap: var(--s-2);
}

.att-big .ic{
  width: 20px;
  height: 20px;
}

/* The closed day. Not a disabled button, because there is nothing left to
   press: a control that exists only to refuse is a question already answered. */
.att-done{
  display: flex;
  align-items: center;
  gap: var(--s-2);
  margin: 0;
  padding: var(--s-3) var(--s-4);
  border: 1px solid var(--green-100);
  border-radius: var(--r);
  background: var(--green-100);
  font-size: 13px;
  font-weight: 500;
  color: var(--green-700);
  animation: fade-in var(--t-base) both;
}

.att-done .ic{
  flex: none;
  width: 18px;
  height: 18px;
}


/* ---------------------------------------------------------------------------
   3. The team panel
   --------------------------------------------------------------------------- */

.att-team{
  animation: rise-in var(--t-base) backwards;
}

.att-team .panel-b{
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}

.att-team-sum{
  margin: 0;
}

.att-group{
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  min-width: 0;
}

.att-group .sec-t .ic{
  width: 14px;
  height: 14px;
}

.att-group-b{
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  min-width: 0;
}

/* The absence group is the only one that needs anybody to act, so its rows
   carry a warm edge. Colour is not the only signal: the badge says "Awaited"
   in words, and the group heading says it again.

   Keyed by the group's own modifier rather than by :first-child, because the
   summary paragraph is the first child of the panel body and a positional
   selector would have matched nothing at all. */
.att-group--awaited .att-person{
  border-color: var(--gold-300);
}

/* Half of these rows are buttons, so their middle column is a <span> rather
   than a <div> and has to be told to stack. mobile.css declares no display on
   .p-m precisely so the atom can be either. */
.att-person .p-m{
  display: block;
}

.att-person .p-tail{
  align-items: flex-start;
}


/* ---------------------------------------------------------------------------
   4. The record
   --------------------------------------------------------------------------- */

.att-rows{
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  min-width: 0;
}

/* The photo is the tallest thing in the row, so the row aligns to its top
   rather than centring a two line meta block against a 44px thumbnail. */
.att-row{
  align-items: flex-start;
  gap: var(--s-3);
}

/* The title line of a row: the date (or the name) takes the space, the badge
   keeps its intrinsic width at the end of it. A div rather than a span, so
   mobile.css's block rule for meta spans never reaches it. */
.att-row-h{
  display: flex;
  align-items: center;
  gap: var(--s-2);
  min-width: 0;
}

.att-row-h b{
  flex: 1 1 auto;
  min-width: 0;
}

.att-row-h .bdg{
  flex: none;
}

.att-who{
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  min-width: 0;
}

.att-list{
  animation: fade-in var(--t-base) both;
}


/* ---------------------------------------------------------------------------
   5. Photos

   A thumbnail is a real button with a real accessible name, and it is 44px
   square whatever the image inside it measures, because it is tapped with a
   thumb next to another one exactly like it.
   --------------------------------------------------------------------------- */

.att-shots{
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: var(--s-1);
}

.att-thumb{
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid var(--gray-200);
  border-radius: var(--r-sm);
  background: var(--gray-100);
  overflow: hidden;
  cursor: pointer;
  transition:
    transform var(--t-base),
    border-color var(--t-fast),
    box-shadow var(--t-base);
}

.att-thumb-img{
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

@media (hover: hover){
  .att-thumb:hover{
    border-color: var(--gold-600);
    box-shadow: var(--sh-md);
    transform: translateY(var(--lift));
    transition-timing-function: var(--ease-spring), var(--ease-out), var(--ease-out);
  }
}

.att-thumb:active{
  transform: translateY(0);
  box-shadow: var(--sh-sm);
  transition:
    transform var(--t-fast),
    border-color var(--t-fast),
    box-shadow var(--t-fast);
}

.att-thumb:focus-visible{
  box-shadow: var(--focus-ring);
}

/* A photo that was never taken, or that the retention sweeper has already
   removed. A short line, never a broken image: a torn page icon reads as a
   fault in the app rather than as a fact about the record. */
.att-gone{
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 var(--s-2);
  border: 1px dashed var(--gray-300);
  border-radius: var(--r-sm);
  font-size: 10.5px;
  text-align: center;
}

.att-photo-big{
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}

.att-photo-img{
  display: block;
  width: 100%;
  max-width: 320px;
  margin-inline: auto;
  border-radius: var(--r);
  background: var(--gray-100);
}

.att-photo-cap{
  margin: 0;
  text-align: center;
}


/* ---------------------------------------------------------------------------
   6. The capture dialog

   A square viewfinder, capped at the size the photo is actually stored at, so
   nobody is framing a face inside a box larger than the picture that will be
   kept. One control under it, and one control only.
   --------------------------------------------------------------------------- */

/* The viewfinder is the whole dialog, so the shell gives it back the side
   gutters it does not need. The photo dialog keeps the standard inset. */
.att-cam-modal .ui-dialog-inner{
  padding: var(--s-4);
}

.att-cam{
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}

.att-cam-stage{
  position: relative;
  width: 100%;
  max-width: 320px;
  margin-inline: auto;
  aspect-ratio: 1 / 1;
  border-radius: var(--r-lg);
  background: var(--navy-900);
  overflow: hidden;
  animation: fade-in var(--t-base) both;
}

.att-cam-stage--busy{
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--s-5);
  background: var(--gray-100);
}

.att-cam-wait{
  margin: 0;
  text-align: center;
}

/* object-fit:cover crops rather than squashes: a face stretched to fill a
   square is worse than a face with its shoulders cut off. */
.att-cam-video,
.att-cam-shot{
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The front camera shows a face the way a mirror does, and the still waiting
   to be sent keeps the same side, so raising the right hand moves the right
   side of the picture. Only the screen is flipped: the photo itself is drawn
   and stored as the lens saw it, so writing behind the person reads true. */
.att-cam-video,
.att-cam-shot{
  transform: scaleX(-1);
}

.att-cam-hint,
.att-cam-size{
  margin: 0;
  font-size: 12.5px;
  color: var(--muted);
  text-align: center;
}

.att-cam-acts{
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
}

/* Retake and Send share a row above the sheet's own footer. Send is wider than
   Retake because they are not equal choices: one is the way forward. */
.att-cam-acts--two{
  flex-direction: row;
  align-items: stretch;
}

.att-cam-acts--two .att-cam-retake{
  flex: 1 1 0;
  min-height: 56px;
}

.att-cam-acts--two .att-big{
  flex: 2 1 0;
}

/* The shutter. The largest control in the application, on purpose. */
.att-shutter{
  min-height: 60px;
  font-size: 16px;
}

.att-shutter .ic{
  width: 22px;
  height: 22px;
}

.att-cam-problem{
  gap: var(--s-3);
  text-align: center;
}


/* ---------------------------------------------------------------------------
   7. The error state

   Every block on this screen fails on its own, so this card appears in three
   different places and has to sit correctly in all of them.
   --------------------------------------------------------------------------- */

.att-error{
  gap: var(--s-2);
  text-align: center;
  animation: fade-in var(--t-base) both;
}


/* ---------------------------------------------------------------------------
   8. Phones - at and below the shell breakpoint

   The card grows rather than shrinks here: the whole screen is the card, so
   there is no competition for the space.
   --------------------------------------------------------------------------- */

@media (max-width: 860px){

  .att-today{
    gap: var(--s-4);
    padding: var(--s-5) var(--s-4);
  }

  .att-today-date{
    font-size: 22px;
  }

  /* Two facts across at 320px, the roster and the check in, each with room
     for its time and its badge. A third column here would wrap both. */
  .att-marks{
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .att-big{
    min-height: 56px;
    font-size: 16px;
  }

  /* The thumbnail moves under the meta line rather than beside it: at 320px
     a 44px photo on the right squeezes the date, the badge and the time. */
  .att-row{
    flex-wrap: wrap;
  }

  .att-row .att-shots{
    width: 100%;
    justify-content: flex-start;
  }

  /* One figure per row. Three 160px tiles in a 288px column would each be
     narrower than their own label. */
  .att-stats{
    grid-template-columns: minmax(0, 1fr);
  }
}


/* ---------------------------------------------------------------------------
   9. Print

   The record prints; the controls and the photo thumbnails do not.
   A sheet of paper cannot be filtered, so a summary line that describes a
   filter would be a claim the reader cannot check.
   --------------------------------------------------------------------------- */

@media print{

  .att-today-act,
  .att-filters,
  .att-chips,
  .att-summary,
  .att-pager,
  .att-shots{
    display: none;
  }

  .att-today,
  .att-team,
  .att-list,
  .att-error{
    animation: none;
  }
}
