/* ==========================================================================
   Line items — one row per record for lists that don't deserve a card.

   Imported from the "Line Item" design project. Same rules as list-blocks.css:
   every value resolves through variables.css, nothing invents a color, radius,
   shadow or type size that isn't already a token.

   The panel and its bands live here too — .list-panel wraps either a list of
   rows or a .panel-body of anything else, so a panel is not only a frame for
   line items. The bands arrived with the class details page and moved here
   once the attendance pages picked them up. They are written up in the design
   project's README under "Panel bands"; the .dc.html artboards there still
   draw the rows only.

   Name reads first, meta sits at the end of the content, a hairline separates
   the content from a fixed-width action rail on the right. Two actions per row
   is the ceiling — a third belongs on the record's own page.

     <div class="list-panel">
       <div class="list-panel-header">          <!-- optional -->
         <h2>Labels</h2>
         <a>Add a label</a>
       </div>
       <ul class="line-items">                  <!-- or <div class="panel-body"> -->
         <li>
           <div class="line-item">
             <span class="line-item-name">…</span>
             <span class="line-item-meta">…</span>    <!-- optional -->
             <span class="line-item-rule"></span>
             <div class="line-item-actions">
               <a class="line-item-action">Edit</a>
               <button class="line-item-action destructive">Delete</button>
             </div>
           </div>
         </li>
       </ul>
       <div class="panel-footer"><a>All labels</a></div>   <!-- optional -->
     </div>

   LOAD ORDER — `stylesheet_link_tag :app` sorts logical paths alphabetically,
   so this file loads BEFORE list-blocks, main and utilities. Anything here
   that has to beat one of those rules wins on specificity, not on order:

     - Action-rail buttons are written as `.line-item-actions` + the same
       element/attribute selectors utilities.css uses, one level deeper, and
       every hover state is restated so utilities' own `:hover` rules (which
       tie on specificity and load later) don't take the row back.
     - Inline-edit inputs override main.css's full-width field rule the same
       way, through `.line-item-field`.
   ========================================================================== */


/* --------------------------------------------------------------------------
   1. PANEL — the surface the rows sit on.

   Rows carry a top border, so the first one doubles as the divider under the
   panel header. With no header there is nothing to divide, so the leading
   border comes off.
   -------------------------------------------------------------------------- */

.list-panel {
  background: var(--nieve);
  border: 3px solid var(--nieve);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

/* Stacked panels — two rosters on one page, say — need air between them. */
.list-panel + .list-panel {
  margin-top: var(--space-6);
}

/* A panel that hosts a popover — a record search, a collection picker in its
   header — has to give up the clip, or the popover is cut off at the panel
   edge. The clip is also what rounds the last row's hover tint into the panel
   corner, so that gets restated on the row itself.

   3px is the panel's own border, so the inner radius is the outer one less
   the border it sits inside. */
.list-panel.has-popover {
  overflow: visible;
}

.list-panel.has-popover ul.line-items > li:last-child .line-item {
  border-bottom-left-radius: calc(var(--radius-xl) - 3px);
  border-bottom-right-radius: calc(var(--radius-xl) - 3px);
}

.list-panel-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  padding: 1.125rem var(--space-6) 0.875rem;
}

/* A count chip beside the heading holds its label on one line. It is a short
   phrase, and a wrapped one reads as two chips stacked — which is what a long
   class title did to it once the label grew past a bare number. Same `flex:
   none` a chip gets inside .line-item-person, and for the same reason. */
.list-panel-header h2 .chip {
  flex: none;
  white-space: nowrap;
}

/* The header's action slot is a link by default, which sits on the heading's
   baseline. A filled button doesn't — its box would hang below the display
   type — so a panel whose header carries one centres the row instead. */
.list-panel-header.has-button {
  align-items: center;
}

.list-panel-header h2 {
  margin: 0;
  /* Flex so a count chip beside the name centres against the display type
     rather than sitting on its baseline. A heading with no chip is unchanged. */
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-family-display);
  font-weight: var(--fw-black);
  font-size: 1.5rem;
  line-height: var(--lh-heading);
  color: var(--vn-heading);
}

.list-panel-header a {
  font-size: 0.9375rem;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}


/* --- Bands: the body, the footer and the header's action cluster ----------

   A panel is a stack of bands. The header names it and carries one verb; the
   body or a list of rows holds the content; the footer is the quiet door to
   the rest of it.

     <section class="list-panel">
       <div class="list-panel-header has-button">
         <h2>People <span class="chip">14</span></h2>
         <a class="button small">Invite people to join</a>   <!-- one verb -->
       </div>
       <div class="panel-body">…</div>                       <!-- or ul.line-items -->
       <div class="panel-footer"><a>Manage people</a></div>   <!-- the door -->
     </section>

   One filled button per header and one quiet link per footer is what gives a
   page of panels its rhythm: every panel answers "what can I do here" in the
   same place, and "where is the rest of it" in the same place.
   ------------------------------------------------------------------------ */

.panel-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

/* The header's own bottom padding is the gap above this, so the body only
   needs enough of its own to keep content off the header's baseline. */
.panel-body {
  padding: var(--space-2) var(--space-6) var(--space-6);
}

/* Same side padding and hairline as .line-item-empty, so a footer under a
   list of rows continues the rows rather than starting something new. */
.panel-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
  padding: 0.875rem var(--space-6);
  border-top: 1px solid var(--color-border);
  font-size: var(--fs-small);
}

/* Underlined on hover only, the way .line-item-name and the panel header's
   own link behave — a permanent rule under every panel's footer would draw a
   second hairline right beneath the real one. */
.panel-footer a {
  font-weight: 500;
  text-decoration: none;
}

.panel-footer a:hover {
  text-decoration: underline;
}

/* A second door, at the far end and a size down: a count of work in progress
   rather than a destination the way "View all messages" is. */
.panel-footer .panel-footer-note {
  margin-left: auto;
  font-size: var(--fs-meta);
  color: var(--color-text-muted);
}

/* What a panel says when it has nothing in it yet, inside .panel-body. A list
   with no rows uses .line-item-empty instead — that one belongs to the list. */
.panel-empty {
  margin: 0;
  padding: var(--space-2) 0 var(--space-3);
  font-size: var(--fs-small);
  line-height: 1.6;
  color: var(--color-text-muted);
}

/* An avatar cluster inside a panel body carries full-size dots rather than a
   card's small ones, so the groups need more air between them than a card
   gives. .people-groups itself belongs to list-blocks.css. */
.panel-body .people-groups {
  gap: var(--space-8);
}


/* --- The identity band: a record's own heading, inside a panel ------------

   A .list-panel with no header band, because the record's name IS the
   heading. Whatever identifies the record leads the row — a person's avatar,
   a document's rendered first page — and the facts sit under the name.

   Lives here rather than in people.css because a document's show page uses
   the same band. Only the leading element differs, and each page brings its
   own.
   -------------------------------------------------------------------------- */

.identity {
  display: flex;
  align-items: flex-start;
  gap: var(--space-6);
  /* The band has no header above it to space itself against, so it supplies
     the top padding .panel-body normally inherits from one. */
  padding-top: var(--space-6);
}

.identity-text {
  flex: 1;
  min-width: 0;
}

/* A chip sits beside the name, and wraps under it before the name has to
   shrink. */
.identity-heading {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.identity-name {
  margin: 0;
  font-family: var(--font-family-display);
  font-weight: var(--fw-black);
  font-size: var(--fs-h2);
  line-height: var(--lh-heading);
  color: var(--vn-heading);
}

/* Three facts, three columns. Fixed rather than auto-fitting: the columns
   line up with the panels below at every desktop width, and a long value
   wraps inside its own column instead of widening it. */
.identity-facts {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-4) var(--space-6);
  margin: var(--space-4) 0 0;
}

.identity-fact {
  min-width: 0;
}

/* A fact that runs the full row — a set of chips, say, which reads badly
   squeezed into a third of the band. */
.identity-fact.wide {
  grid-column: 1 / -1;
}

.identity-fact dt {
  margin: 0 0 0.125rem;
  font-size: 0.8125rem;
  font-weight: var(--fw-bold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1.6;
  color: var(--color-text-muted);
}

.identity-fact dd {
  margin: 0;
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--carbon);
  /* An email address with no spaces in it is the one value that can't wrap on
     its own, and it's the one most likely to be long. */
  overflow-wrap: anywhere;
}

.identity-fact dd a {
  text-decoration: none;
}

.identity-fact dd a:hover {
  text-decoration: underline;
}


/* --------------------------------------------------------------------------
   2. LIST
   -------------------------------------------------------------------------- */

ul.line-items {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* A <turbo-frame> is inline by default; the rows it wraps are grids. */
ul.line-items turbo-frame {
  display: block;
}

ul.line-items:first-child > li:first-child .line-item {
  border-top: none;
}

/* Empty notice. It ships inside the list rather than beside it so that a list
   fed by turbo streams corrects itself: the notice hides the moment a row
   lands next to it, and comes back when the last one is removed. */
.line-item-empty {
  padding: 1.25rem var(--space-6);
  border-top: 1px solid var(--color-border);
  font-size: var(--fs-small);
  line-height: 1.6;
  color: var(--color-text-muted);
}

ul.line-items > li.line-item-empty:not(:only-child) {
  display: none;
}


/* --------------------------------------------------------------------------
   3. ROW — 76px tall on a border-box, four columns.

   The 1px hairline is decorative; the 1.5rem gap on either side of it is what
   actually separates content from actions. Name truncates; meta and the
   action rail never shrink.
   -------------------------------------------------------------------------- */

.line-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto 1px auto;
  align-items: center;
  gap: 0 var(--space-6);
  box-sizing: border-box;
  min-height: 76px;
  padding: var(--space-2) var(--space-6);
  border-top: 1px solid var(--color-border);
}

/* Lists with no useful count drop the meta column rather than leaving an
   empty track with a gap on both sides of it. */
.line-item:not(:has(.line-item-meta)) {
  grid-template-columns: minmax(0, 1fr) 1px auto;
}

/* The same, for the other end: a list where no row has anything to do *to* it
   drops the rail and the hairline it hangs off, so the meta sits in the
   panel's gutter rather than 73px inside it — 1px of rule and the 1.5rem gap
   on either side of it. Rows that render an empty .line-item-actions (a roster
   row whose reader may not remove anybody) keep the rail, which is what holds
   a list's action column in one place whether or not every row fills it. */
.line-item:not(:has(.line-item-actions)) {
  grid-template-columns: minmax(0, 1fr) auto;
}

/* Only a row with something to click lights up. The tint is a promise that
   the row responds, and on a purely informational one — a survey answer, a
   reason somebody cannot be deleted — it promises a click that goes nowhere.

   Two ways to qualify, because rows are built two ways: the row IS the link
   (`a.line-item.is-linked`, which is most of them), or it CONTAINS one — a
   link or a form control in the action rail, or a link in the name.

   A row whose rail comes out empty because its reader may not do anything to
   that record is correctly excluded: there is nothing there to click, whatever
   the markup reserved. The rail's own tracks stay, so the column still lines
   up down the list — that is a layout question and this is not. */
a.line-item:hover,
.line-item:has(a, button, input[type="submit"]):hover {
  background: var(--color-surface-row-hover);
}

/* A person's row leads with their avatar and can carry a role badge after the
   name. The group is the grid item; the name inside it is what truncates, so
   the badge is never the thing that gets cut off.

   Rows whose record is not a person put .line-item-name straight in the track
   as before — this is additive, not a replacement. */
.line-item-person {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}

.line-item-person .chip {
  flex: none;
}

/* Rows are data, not prose — 140% here against the brand's 180% body. */
.line-item-name {
  min-width: 0;
  font-size: 1.0625rem;
  font-weight: var(--fw-bold);
  line-height: 1.4;
  color: var(--carbon);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.line-item-name a {
  color: inherit;
  text-decoration: none;
}

.line-item-name a:hover {
  color: var(--color-link);
  text-decoration: underline;
}

.line-item-meta {
  font-size: var(--fs-meta);
  line-height: 1.4;
  color: var(--color-text-muted);
  white-space: nowrap;
}

.line-item-rule {
  width: 1px;
  height: 26px;
  background: var(--color-border);
}

.line-item-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* button_to wraps its button in a form; the form is the flex item. */
.line-item-actions form.button_to {
  display: flex;
  margin: 0;
}


/* --- The action rail ------------------------------------------------------

   Deliberately not the theme's filled pájaro-azul button: at one per row a
   filled button turns the list into a wall of blue. The filled button stays
   for page-level actions.
   -------------------------------------------------------------------------- */

.line-item-actions .line-item-action,
.line-item-actions BUTTON:not(.editor-button),
.line-item-actions INPUT[type="submit"] {
  display: inline-flex;
  align-items: center;
  height: 38px;
  padding: 0 0.9375rem;
  border: 1px solid var(--brisa);
  border-radius: var(--radius-md);
  background: var(--nieve);
  color: var(--color-link);
  font-family: var(--font-family-base);
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  box-shadow: none;
  cursor: pointer;
  transition: background-color 0.2s linear;
}

.line-item-actions .line-item-action:hover,
.line-item-actions BUTTON:not(.editor-button):hover,
.line-item-actions INPUT[type="submit"]:hover {
  background: var(--niebla);
  color: var(--color-link);
}

/* Destructive: hollín rather than hierro. Grey drops below 4.5:1 on white and
   reads as disabled next to the blue primary. */
.line-item-actions .line-item-action.destructive,
.line-item-actions BUTTON.destructive:not(.editor-button),
.line-item-actions INPUT[type="submit"].destructive {
  border-color: var(--color-border);
  color: var(--hollin);
  transition: color 0.2s linear, border-color 0.2s linear;
}

.line-item-actions .line-item-action.destructive:hover,
.line-item-actions BUTTON.destructive:not(.editor-button):hover,
.line-item-actions INPUT[type="submit"].destructive:hover {
  background: var(--nieve);
  border-color: var(--tomate);
  color: var(--tomate);
}

/* utilities.css puts margin-left on adjacent buttons and button_to forms; the
   flex gap already spaces the rail. Mirrors its selectors one level deeper. */
.line-item-actions A + A,
.line-item-actions A + FORM.button_to,
.line-item-actions BUTTON:not(.editor-button) + BUTTON:not(.editor-button),
.line-item-actions FORM.button_to + FORM.button_to,
.line-item-actions > * + * {
  margin-left: 0;
}


/* --- A row that is one link ----------------------------------------------

   A row with nothing to do *to* it — the whole row opens the record — so the
   action rail and its hairline come off and the grid drops to two tracks.
   ------------------------------------------------------------------------ */

.line-item.is-linked {
  grid-template-columns: minmax(0, 1fr) auto;
  text-decoration: none;
}

/* The whole row lights up, but only its own leading text takes the underline
   — the same hover .line-item-name gives a link nested inside it. */
.line-item.is-linked:hover .line-item-name {
  color: var(--color-link);
  text-decoration: underline;
}

/* Two lines in the first track: what the row says, and who it came from. */
.line-item-stack {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  min-width: 0;
}

.line-item-sub {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  font-size: var(--fs-meta);
  line-height: 1.4;
  color: var(--color-text-muted);
}

.line-item-sub svg {
  flex: none;
  width: 0.875rem;
  height: 0.875rem;
}

/* Where the sub-line carries a filename, that is the only part long enough to
   need cutting. */
.line-item-sub .line-item-sub-truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}


/* --------------------------------------------------------------------------
   4. INLINE EDIT — a row that turns into its own form.

   Used where the record has exactly one user-editable field, so the whole
   edit fits the row band and never needs a page. Anything with more than one
   field links out to its edit screen instead.
   -------------------------------------------------------------------------- */

.line-item-field {
  min-width: 0;
}

.line-item-field input[type="text"] {
  width: 100%;
  max-width: none;
  font-size: var(--fs-small);
  line-height: 1.5;
}

/* Carries role="alert" so the failure is announced, which would otherwise pick
   up main.css's full alert box — reset back to a line of red text. */
.line-item-field .line-item-error {
  display: block;
  margin-top: var(--space-1);
  padding: 0;
  border: none;
  background: none;
  font-size: var(--fs-meta);
  line-height: 1.4;
  color: var(--color-alert-text);
}

/* The save action is the one filled button the pattern allows — inside a form
   the rail needs a clear default for Enter. */
.line-item-actions INPUT[type="submit"].primary,
.line-item-actions BUTTON.primary:not(.editor-button) {
  border-color: var(--pajaro-azul);
  background: var(--pajaro-azul);
  color: var(--trigo);
}

.line-item-actions INPUT[type="submit"].primary:hover,
.line-item-actions BUTTON.primary:not(.editor-button):hover {
  background: var(--gota-de-lluvia);
  color: var(--trigo);
}


/* --------------------------------------------------------------------------
   5. MOBILE — single breakpoint at 768px.

   Name and meta stack, the buttons drop their borders and become text
   actions, and the hairline moves onto the action group as a border-left. The
   whole record stays one 57px band. The 44px hit target is not negotiable.
   -------------------------------------------------------------------------- */

@media (max-width: 48rem) {
  /* Whatever leads the band leads the block rather than sitting beside it: at
     375px a 96px avatar — or a 306px page render — plus a name leaves the name
     about four characters. */
  .identity {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-4);
    padding-top: var(--space-4);
  }

  .identity-facts {
    grid-template-columns: 1fr;
    gap: var(--space-3);
  }

  .list-panel-header {
    padding: var(--space-4) var(--space-4) var(--space-3);
  }

  .list-panel-header h2 {
    font-size: 1.375rem;
  }

  /* A heading and a button don't share a 375px line: the button ends up
     breaking its own label across two lines. It takes the next line instead,
     which space-between leaves flush left under the heading. */
  .list-panel-header.has-button {
    flex-wrap: wrap;
    row-gap: var(--space-3);
  }

  /* Every band takes the same gutter as the header above it. Without this the
     body keeps its 24px while the header and the rows go to 16px, and a
     panel's content sits 8px inside its own heading. */
  .panel-body,
  .panel-footer,
  .line-item-empty {
    padding-left: var(--space-4);
    padding-right: var(--space-4);
  }

  /* --- The person group ----------------------------------------------------

     A badge is flex: none and the name shrinks, so in a column this narrow the
     name loses every pixel to the badge and vanishes — measured at 0px wide
     beside a 111px "Administrator" chip.

     The badge takes a line of its own rather than a share of the first one. A
     width floor on the name would work too, but only until the column got
     narrower than the floor, at which point the avatar is the thing that
     wraps. This holds at any width: avatar and name on the line, badge under
     them.

     Grid rather than a wrapped flex row, because in flex the only way to force
     that break is flex-basis: 100% on the badge — which also stretches it the
     full width of the row, and beats any `width` set alongside it. Spanning
     both columns puts it on its own line; justify-self: start then sizes it to
     fit-content, so it hugs its label. A longer label ("Substitute teacher")
     stays on one line: fit-content resolves to max-content until the label is
     wider than the row itself. */
  .line-item-person {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: var(--space-2);
    row-gap: var(--space-1);
    align-items: center;
  }

  /* The group's own children have to be placed explicitly. .line-item-name
     carries grid-column: 1 for the rows that put it straight into the
     .line-item grid, which was inert while this group was a flex container —
     as a grid it takes effect, and the name lands in the avatar's cell and
     pushes the avatar after it.

     minmax(0, 1fr) on that second track is what lets the name ellipsise rather
     than force the track wider than the column; a bare 1fr floors at
     min-content. */
  .line-item-person .profile-dot {
    grid-column: 1;
    grid-row: 1;
  }

  .line-item-person .line-item-name {
    grid-column: 2;
    grid-row: 1;
  }

  .line-item-person .chip {
    grid-column: 1 / -1;
    justify-self: start;
  }

  .line-item,
  .line-item:not(:has(.line-item-meta)) {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 0 var(--space-4);
    min-height: 0;
    padding: 0.375rem var(--space-4);
  }

  /* .line-item-person has to be named alongside .line-item-name: where a row
     uses the person group, the name is inside it and is no longer the grid
     child, so placing .line-item-name alone would leave the avatar rows
     unplaced. */
  .line-item-person,
  .line-item-name,
  .line-item-field {
    grid-column: 1;
    grid-row: 1;
    font-size: 1rem;
    line-height: 1.35;
  }

  .line-item-meta {
    grid-column: 1;
    grid-row: 2;
    font-size: 0.8125rem;
    line-height: 1.35;
  }

  .line-item-rule {
    display: none;
  }

  .line-item-actions {
    grid-column: 2;
    /* span 2, not 1 / -1: the rows here are implicit, so -1 resolves to the
       end of the (empty) explicit grid and the rail would sit in row 1 alone,
       pushing its 44px target on top of the meta line instead of beside it. */
    grid-row: 1 / span 2;
    gap: 0.875rem;
    border-left: 1px solid var(--color-border);
    padding-left: var(--space-4);
  }

  /* With no meta line there is no second row to straddle — and spanning to one
     the rail itself creates leaves the 44px target centred across 44px while
     the name sits in a 28px first row, so the action rides 8px low against it.
     Mirrors the grid-template rule at the top of section 3. */
  .line-item:not(:has(.line-item-meta)) .line-item-actions {
    grid-row: 1;
  }

  .line-item-actions .line-item-action,
  .line-item-actions BUTTON:not(.editor-button),
  .line-item-actions INPUT[type="submit"] {
    height: auto;
    min-height: 44px;
    padding: 0 0.125rem;
    border: none;
    background: none;
  }

  .line-item-actions .line-item-action:hover,
  .line-item-actions BUTTON:not(.editor-button):hover,
  .line-item-actions INPUT[type="submit"]:hover {
    background: none;
  }

  .line-item-actions .line-item-action.destructive,
  .line-item-actions BUTTON.destructive:not(.editor-button),
  .line-item-actions INPUT[type="submit"].destructive {
    border: none;
  }

  .line-item-actions .line-item-action.destructive:hover,
  .line-item-actions BUTTON.destructive:not(.editor-button):hover,
  .line-item-actions INPUT[type="submit"].destructive:hover {
    background: none;
    color: var(--tomate);
  }

  /* Filled save button: keep the fill, it is the form's default action. */
  .line-item-actions INPUT[type="submit"].primary,
  .line-item-actions BUTTON.primary:not(.editor-button) {
    padding: 0 var(--space-3);
    border: 1px solid var(--pajaro-azul);
    background: var(--pajaro-azul);
  }

  /* A row in edit mode is the one place the band is allowed to grow: sharing
     the width with the action rail leaves ~120px of field, which shows about
     eight characters of a name. Field takes the row, actions drop below it. */
  FORM.line-item {
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
  }

  FORM.line-item .line-item-actions {
    grid-column: 1;
    grid-row: 2;
    justify-content: flex-end;
    border-left: none;
    padding-left: 0;
  }
}
