/* ============================================================
   labels.css — the label generator's own layer
   ------------------------------------------------------------
   Loaded AFTER styles.css, and only by labels.html. Two very
   different things live here, and the split is the point:

   1. The page UI (form, stack list, buttons) — written in the
      shared vocabulary from styles.css: hard 2px ink borders,
      offset shadows, no radius anywhere, Anton/Space Mono/
      Archivo. It should be indistinguishable in feel from the
      collection and statistics pages.

   2. THE LABEL ITSELF — the printed artifact. Frozen. It is
      sized in inches against a real jewel case insert, and it
      predates the site's paper palette on purpose: it's ink on
      white card stock, not construction paper. Nothing in
      section 1 may reach into it.

   Why its own file rather than a section of styles.css: the
   @page rule at the bottom sets letter/portrait/0.3in, and
   @page cannot be scoped to a page or a selector. Living in
   styles.css it would silently re-margin the printed output of
   index.html's list view and stats.html too.
   ============================================================ */


/* ============================================================
   1. Page layout
   ============================================================ */

/* Form beside the sheet on a desk-sized screen; stacked below it on a phone,
   where a 360px form column and a 4.7in label can't share a row. */
.labels-layout {
  display: flex;
  gap: 1.5rem;
  align-items: flex-start;
  flex-wrap: wrap;
}

.form-panel {
  /* Doesn't grow: the label preview should take the slack, since it's the
     thing whose size actually means something. */
  flex: 0 1 22rem;
  min-width: 0;
}

.preview-area {
  flex: 1 1 30rem;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1.5rem;
  /* The label is a fixed physical size — 4.7244in, about 454px — because it's
     cut out and slid into a jewel case. On a phone that's wider than the
     screen, and styles.css hides overflow-x on <body>, so without a scroll
     container of its own the label would simply be clipped with no way to
     reach the rest of it. Shrinking it is not an option: it would no longer
     be the thing that prints. */
  overflow-x: auto;
  /* Room for the scrollbar so it doesn't sit on the label's bottom border. */
  padding-bottom: 0.5rem;
}


/* ============================================================
   2. Form fields
   ============================================================ */

.field { display: flex; flex-direction: column; margin-bottom: 0.9rem; }

.field-label {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--ink-soft);
  margin-bottom: 0.25rem;
}

.field-input,
.field-textarea {
  font-family: var(--font-body);
  font-size: 0.95rem;
  padding: 0.5rem 0.65rem;
  border: 2px solid var(--ink);
  background: var(--surface);
  color: var(--ink);
  box-shadow: 3px 3px 0 var(--ink);
  width: 100%;
  transition: transform 0.1s var(--ease), box-shadow 0.1s var(--ease);
}
/* Press into the paper on focus — the same gesture as the search field. */
.field-input:focus { transform: translate(3px, 3px); box-shadow: none; }

.field-textarea {
  /* Mono, because this is a list you scan line-by-line for alignment and
     count, not prose. */
  font-family: var(--font-mono);
  font-size: 0.8rem;
  line-height: 1.5;
  height: 11rem;
  resize: vertical;
}
.field-textarea:focus { transform: none; box-shadow: 3px 3px 0 var(--ink); }

.field-input::placeholder,
.field-textarea::placeholder { color: var(--ink-soft); opacity: 0.7; }

.field-hint {
  font-family: var(--font-mono);
  font-size: 0.64rem;
  line-height: 1.45;
  color: var(--ink-soft);
  margin: 0.35rem 0 0;
}
/* The auto-fill readout: same slot, but it reports the result of an action,
   so it gets ink weight rather than the muted hint grey. */
.field-status {
  color: var(--ink);
  min-height: 1.45em;   /* reserve the line so the form doesn't jump */
}


/* ============================================================
   3. Buttons
   ============================================================ */

.btn-row {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-top: 0.9rem;
}

.btn {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink);
  background: var(--surface);
  border: 2px solid var(--ink);
  box-shadow: 2px 2px 0 var(--ink);
  padding: 0.45rem 0.8rem;
  cursor: pointer;
  transition: transform 0.1s var(--ease), box-shadow 0.1s var(--ease),
              background-color 0.1s var(--ease);
}
.btn:hover { background: var(--mustard); }
.btn:active { transform: translate(2px, 2px); box-shadow: none; }
.btn:disabled {
  opacity: 0.5;
  cursor: default;
  transform: none;
  box-shadow: 2px 2px 0 var(--ink);
  background: var(--surface);
}

/* The two actions that commit something: add to the sheet, and print it.
   --orange-deep rather than plain --orange: these labels are small bold caps,
   which AA holds to 4.5:1, and light type on the decorative orange only reaches
   3.19:1. Same fill as "Make label" in the collection's disc dialog, which is
   the button that sends a disc here. */
.btn-primary {
  color: var(--surface);
  background: var(--orange-deep);
}
.btn-primary:hover { background: var(--brick); color: var(--surface); }

/* The way back from a Clear all or a replacing import — on the page only for
   the half-minute the offer stands, and hidden the rest of the time, so it
   appears and disappears in a row that otherwise never changes.

   Mustard held permanently, where every other safe control only goes mustard on
   hover. Same signal for the same reason — this is the button being pointed at
   — and one that has just materialised next to the button you pressed should be
   found by looking, not by hunting for what moved. */
.btn-undo { background: var(--mustard); }
.btn-undo:hover { background: var(--orange); }


/* ============================================================
   4. The print stack
   ============================================================ */

.sheet-count {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink-soft);
  margin: 1.1rem 0 0.4rem;
}

/* Fires when a disc has more tracks than the tightest density step can fit, so
   the card is printing a trimmed list. Brick rather than the hint grey: this is
   the sheet about to lose something, not a note about how to use the form. */
.sheet-warning {
  color: var(--brick-ink);
  font-weight: 700;
  margin: 0 0 0.6rem;
}

.stack-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

/* The row is a container, not a control: it holds two separate buttons (load
   for edit, remove), and a button can't legally nest inside another one. The
   border and shadow live here so the pair still reads as a single row. */
.stack-item {
  display: flex;
  align-items: stretch;
  border: 2px solid var(--ink);
  background: var(--surface);
  box-shadow: 2px 2px 0 var(--ink);
}

/* The row currently loaded into the form, inverted so it's obvious which
   entry the fields belong to. */
.stack-item.is-editing {
  background: var(--ink);
  color: var(--paper);
  box-shadow: 2px 2px 0 var(--ink-soft);
}

.stack-name {
  flex: 1 1 auto;
  min-width: 0;
  text-align: left;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  line-height: 1.35;
  overflow-wrap: anywhere;
  background: none;
  border: none;
  color: inherit;
  padding: 0.4rem 0.5rem;
  cursor: pointer;
}
.stack-name:hover { background: var(--mustard); color: var(--ink); }

/* The inversion above is the only thing that says "this row is in the form",
   and forced-colors mode discards it: --ink and --paper both collapse to the
   system pair, so the loaded row comes back looking exactly like its
   neighbours. Border widths survive forced colors where fills don't, so the
   state gets a rule under the row's name as well as the fill. currentColor so
   it flips with the inversion — paper on the dark row, ink once the name is
   hovered — instead of hard-coding one side of it.

   On .stack-name rather than on .stack-item, which is where the state class
   actually sits: the row's own bottom edge is where the buttons' focus ring
   lands (3px, offset 2px, so it covers 2-5px outside the button), and a state
   rule sitting under it would be painted over at exactly the moment someone is
   navigating by keyboard. Inside the button the ring is drawn around it and the
   two never meet. The 3px comes back out of the padding, so loading a row for
   edit doesn't make it 3px taller and shove the rest of the stack down. */
.stack-item.is-editing .stack-name {
  border-bottom: 3px solid currentColor;
  padding-bottom: calc(0.4rem - 3px);
}

/* Destructive, so it separates from the row with a rule and goes brick on
   hover rather than joining the mustard family the safe controls use. */
.stack-remove {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  background: none;
  border: none;
  border-left: 2px solid var(--ink);
  color: var(--brick-ink);
  cursor: pointer;
  padding: 0.4rem 0.55rem;
}
.stack-remove:hover { background: var(--brick-ink); color: var(--surface); }
.stack-item.is-editing .stack-remove {
  border-left-color: var(--paper);
  color: var(--mustard);
}
.stack-item.is-editing .stack-remove:hover { background: var(--brick); color: var(--surface); }

.empty-state {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  line-height: 1.6;
  color: var(--ink-soft);
  padding: 2.5rem 1.5rem;
  border: 2px dashed var(--ink-soft);
  text-align: center;
  width: 100%;
}


/* ============================================================
   5. THE LABEL — frozen artifact, do not restyle
   ============================================================
   Everything below reproduces the jewel-case insert exactly as it printed
   before this page adopted the site's chrome. Sizes stay in px and inches
   (they're measured against physical card stock, not the page's rem scale),
   and the palette stays pure black on white.

   The two declarations marked INHERITANCE GUARD are the only additions. They
   are not new styling — they re-state values the label used to get for free
   from a page whose <body> set neither. styles.css sets both, so without
   these the label would silently pick up 1.45 line-height and warm --ink
   type, which reflows the tracklist and tints the print.
   ============================================================ */

:root {
  --label-size: 4.7244in; /* standard jewel case front insert, 120mm */
}

.label {
  width: var(--label-size);
  height: var(--label-size);
  border: 6px solid #000;
  background: #fff;
  padding: 0.3in;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  font-family: 'Helvetica Neue', Arial, sans-serif;
  color: #111;            /* INHERITANCE GUARD — was body's color */
  line-height: normal;    /* INHERITANCE GUARD — was body's default */
  /* No margin-bottom: the preview column owns the gap between labels now.
     Print restores its own spacing below. */
  flex: 0 0 auto;
  /* Last resort. The density ladder below is what actually makes long
     tracklists fit; this only catches the disc so long that even the tightest
     step overflows, and turns a tail of type spilling across the page into a
     clean crop at the border. The form warns when it fires. */
  overflow: hidden;
}

.label-category {
  font-size: 15px;
  font-weight: 900;
  letter-spacing: 3px;
  text-transform: uppercase;
  border-bottom: 4px solid #000;
  padding-bottom: 6px;
  margin-bottom: 10px;
}

.label-main {
  /* Step 0 of the header ladder: the original measured values. */
  --head-artist: 17px;
  --head-title: 30px;
  --head-year: 13px;
  --head-pad: 10px;
  --head-title-gap: 8px;
  --head-year-gap: 10px;

  flex-grow: 1;
  /* But never gives room back on its own. When the card is over budget, flex
     would take the deficit out of every item in proportion, silently and by an
     amount nobody chose. The header does give room back — it's the first thing
     that does — but through the ladder below, in measured steps. */
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
  border-bottom: 4px solid #000;
  padding: var(--head-pad) 0;
}

.label-artist {
  font-size: var(--head-artist);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  word-break: break-word;
}

.label-title {
  font-size: var(--head-title);
  font-weight: 900;
  text-transform: uppercase;
  line-height: 1.05;
  letter-spacing: 1px;
  margin-top: var(--head-title-gap);
  word-break: break-word;
  text-wrap: balance;
}

.label-year {
  font-size: var(--head-year);
  font-weight: 700;
  margin-top: var(--head-year-gap);
  letter-spacing: 2px;
}

/* ---- The header ladder -----------------------------------------------
   Spent BEFORE the tracklist gives up anything. The artist and title are set
   large because they're what you read from across the room while the case is
   still on the shelf — but you read them at a glance, and a glance survives
   30px dropping to 20px. The tracklist doesn't work that way: it's read up
   close, one line at a time, and type small enough to defeat that isn't
   holding the information any more, it's just proving the information was
   there. So the display type is the first thing asked to give, and by the
   time step 3 is reached the title is still nearly twice the size of a track.

   The gaps and padding come down with the type: at 19px the original 10px of
   air around the block reads as a gap someone forgot to close.
   ---------------------------------------------------------------------- */

.label[data-head="1"] .label-main {
  --head-artist: 15px; --head-title: 26px; --head-year: 12px;
  --head-pad: 9px; --head-title-gap: 7px; --head-year-gap: 8px;
}
.label[data-head="2"] .label-main {
  --head-artist: 13.5px; --head-title: 22px; --head-year: 11px;
  --head-pad: 8px; --head-title-gap: 6px; --head-year-gap: 7px;
}
.label[data-head="3"] .label-main {
  --head-artist: 12px; --head-title: 19px; --head-year: 10px;
  --head-pad: 7px; --head-title-gap: 5px; --head-year-gap: 6px;
}

.label-tracks {
  /* Step 0 of the density ladder: the original measured values, and what every
     disc that fits in two comfortable columns still gets. */
  --track-size: 10.5px;
  --track-leading: 1.5;
  --track-cols: 2;
  --track-gap: 14px;
  --track-num-w: 16px;
  --track-pad: 8px;

  font-size: var(--track-size);
  font-weight: 700;
  text-transform: uppercase;
  line-height: var(--track-leading);
  padding-top: var(--track-pad);
  column-count: var(--track-cols);
  column-gap: var(--track-gap);
  /* Height stays intrinsic — no shrinking. A multicol box with a definite
     height doesn't grow downward when it runs out of room, it spills sideways
     into overflow columns, which would make the tracklist unmeasurable in the
     one direction the fitter cares about. Left alone it balances into
     --track-cols and grows down, so how far past the label's bottom edge it
     reaches is exactly how much it doesn't fit by. */
  flex: 0 0 auto;
}

.label-tracks div {
  break-inside: avoid;
  display: flex;
}

.track-num {
  width: var(--track-num-w);
  flex-shrink: 0;
}

/* The title beside the number. At three columns a column is barely 1.2in wide,
   and a flex item won't wrap below its longest word by default — one
   "INSTRUMENTAL)" would push the column into its neighbour. */
.label-tracks div span:not(.track-num) {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* The "+12 more" row labels.js substitutes for the tracks it had to drop. Set
   apart with a rule and a wider gap so it reads as a footnote about the list
   rather than as the last thing on it. */
.track-more {
  margin-top: 4px;
  padding-top: 3px;
  border-top: 1px solid #000;
}

/* ---- The density ladder ----------------------------------------------
   The second ladder, and the one the card is most reluctant to climb: it isn't
   touched until the header ladder above is spent. labels.js sets data-density
   and stops at the first step whose tracklist fits inside the card. Nothing
   here is responsive to the viewport — the label is 120mm of card stock at
   every screen size, so what it responds to is the tracklist itself: how many
   tracks there are and how long their titles run.

   The order is by readability, not by size, and those aren't the same thing.
   A third column is not simply "denser": it makes each column about 1.2in
   wide, and a title that used to sit on one line now wraps to two, so three
   columns of 8px type can run TALLER than two columns of 8.25px. That's why
   the two-column run goes all the way down to 7.5px before step 5 splits: for
   a disc with real song titles, two columns of slightly smaller type both fits
   better and reads better than three columns of slightly larger. Steps 5-6
   exist for the discs the split does help — samplers and hardcore records,
   where forty titles are each two words long.

   The gap, the number gutter and the top padding come down with the type so
   the columns keep their proportions instead of turning into thin ribbons of
   text with a canyon between them.
   ---------------------------------------------------------------------- */

.label[data-density="1"] .label-tracks {
  --track-size: 9.75px; --track-leading: 1.4; --track-gap: 13px; --track-num-w: 15px;
}
.label[data-density="2"] .label-tracks {
  --track-size: 9px; --track-leading: 1.35; --track-gap: 12px; --track-num-w: 14px; --track-pad: 7px;
}
.label[data-density="3"] .label-tracks {
  --track-size: 8.25px; --track-leading: 1.3; --track-gap: 11px; --track-num-w: 13px; --track-pad: 6px;
}
.label[data-density="4"] .label-tracks {
  --track-size: 7.5px; --track-leading: 1.22; --track-gap: 10px; --track-num-w: 12px; --track-pad: 5px;
}
/* Three columns from here down. */
.label[data-density="5"] .label-tracks {
  --track-size: 8px; --track-leading: 1.3; --track-cols: 3; --track-gap: 10px; --track-num-w: 12px; --track-pad: 6px;
}
/* The floor. 7.25px bold caps is small, but it's still type you can read off a
   card held at arm's length, which is the whole job. There was a 6.5px step
   below this one and it's gone on purpose: it fit more tracks and none of them
   could be read, which is not a card with a longer tracklist, it's a card with
   a grey smudge along the bottom. Past this point labels.js stops shrinking and
   starts dropping tracks, which at least tells the truth about what's there. */
.label[data-density="6"] .label-tracks {
  --track-size: 7.25px; --track-leading: 1.25; --track-cols: 3; --track-gap: 9px; --track-num-w: 11px; --track-pad: 5px;
}


/* ============================================================
   6. Print
   ============================================================
   The sheet is the only thing on paper: the site chrome, the form, and the
   stack list all go. What's left is a bare column of labels, two to a page.
   ============================================================ */

@media print {
  @page {
    size: letter portrait;
    margin: 0.3in;
  }

  body {
    background: #fff;
    padding: 0;
    margin: 0;
  }

  /* styles.css already drops .grain and .site-footer in print, but it also
     gives .site-header a rule line — right for a printed disc list, wrong
     here, where the header isn't part of the artifact at all. */
  .site-header,
  .form-panel,
  .no-print { display: none !important; }

  .site-main,
  .labels-layout,
  .preview-area {
    display: block;
    margin: 0;
    padding: 0;
    max-width: none;
    /* The screen's horizontal scroll container would otherwise become a
       clipping box on paper, cropping every label at the page edge. */
    overflow: visible;
  }

  .label {
    border: 6px solid #000;
    page-break-inside: avoid;
    margin: 0.1in auto;
  }
  .label:nth-child(2n) {
    page-break-after: always;
  }
}
