/**
 * Keepsake builder (/create-keepsake).
 *
 * Deliberately mirrors css/order.css so the two builders read as one shop.
 * The page-count strip spans the full width above TWO columns instead of
 * three, and the options column takes exactly the space the photo page gives
 * its first two columns combined (330 + 24 gap + 450 = 804), with the summary
 * keeping its 550. Total width is therefore identical to the photo page.
 *
 * The shared shell classes (.tl-app-header, .tl-checkout-button) are repeated
 * here rather than shared, because order.css is not loaded on this page — the
 * two libraries are never on screen together.
 */

/* Break out of the DXPR content container, exactly as .tl-order-app does. */
.tl-keepsake-app {
  width: 100vw;
  max-width: none;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  background: #ced1cd;
}

.tl-keepsake-app .tl-app-header {
  padding: 28px 40px 0;
}

.tl-keepsake-notice {
  margin: 24px 40px 0;
  padding: 14px 18px;
  border: 1px solid #e2c98f;
  background: #fdf6e6;
  border-radius: 10px;
  color: #6b5320;
}

/* The page-count strip's rules lived here — .tl-keepsake-count and its own
   .tl-keepsake-stepper — and went with the strip on 2026-08-24. Note the
   per-label quantity steppers are the SHARED .tl-stepper component and are
   untouched by that removal. Do not confuse .tl-keepsake-counter, further
   down, with the strip: that one counts characters in a title. */

/* The standard for ALL help text on this page, matching .tl-photo-page-help
   on the photo builder. Any new hint should use this class rather than
   inventing its own size or colour. */
.tl-keepsake-help {
  display: block;
  margin-top: 6px;
  font-size: 20px;
  color: #777;
}

/* Two columns, matching the photo page's total width --------------------- */

/**
 * Three columns, the same shape create-photo uses (330 / minmax(450) / 550),
 * widened where this page needs it: the title column has to show all 60
 * characters of a story title at once, and column 3 gave up the 80px that
 * column 2 needed for the longest label name.
 *
 * A 60-character title still WRAPS in the summary, and that is accepted: it is
 * the only place on the page where it happens.
 */
.tl-keepsake-body {
  display: grid;
  /**
   * 470 / 450 / 550 — eighty pixels moved from column 2's FLOOR to column 3,
   * in two goes on 2026-08-28 and 29, because the summary kept wrapping the
   * longest label name onto a second line.
   *
   * The arithmetic, measured rather than guessed. The summary line reads
   * "6 - Removable Waterproof White QR Code Labels" and needs 467px. Column 3
   * is a FIXED track, so its width is the same at every screen size and is the
   * only thing that decides whether that line wraps: at 470 it had 430 after
   * its 20px of padding either side and wrapped; at 520 it had 480, which was
   * 13px of headroom once the quantity was put back in front of the name; at
   * 550 it has 510, which is 43px.
   *
   * Column 2 pays for it and barely notices: it is the 1fr track, so it takes
   * all the slack on a wide screen — 716px at 1864px of viewport, against the
   * 565 its own longest row needs. Only its FLOOR moved, which is felt solely
   * between the 1560px stacking breakpoint and about 1650px, where its longest
   * row already wrapped before any of this.
   *
   * The three floors still add up to 1470, so the total is unchanged and the
   * breakpoint below still lands in the same place.
   */
  grid-template-columns: 470px minmax(450px, 1fr) 550px;
  gap: 24px;
  align-items: start;
  padding: 24px 40px 28px;
  box-sizing: border-box;
}

.tl-keepsake-title-panel,
.tl-keepsake-options,
.tl-keepsake-summary {
  background: #efefef;
  border: 1px solid #ddd;
  border-radius: 10px;
  padding: 20px;
  min-width: 0;
  box-sizing: border-box;
}

/* No font-size or family here on purpose: the photo page lets the theme style
   its section headings (Playfair Display), and overriding would make the two
   builders look like different sites. Spacing only. */
.tl-keepsake-title-panel h3,
.tl-keepsake-options h3,
.tl-keepsake-summary h3 {
  margin: 0 0 16px;
}

/* The three columns are three steps, so they are numbered. Large enough to
   read as a step rather than a bullet. */
.tl-keepsake-step {
  display: inline-block;
  margin-right: 12px;
  width: 34px;
  height: 34px;
  line-height: 34px;
  text-align: center;
  border-radius: 50%;
  background: #2e8b57;
  color: #fff;
  font-size: 19px;
  font-weight: 700;
  vertical-align: -6px;
}

/* Column 1 ---------------------------------------------------------------- */

.tl-keepsake-title-panel .tl-keepsake-title {
  display: block;
  width: 100%;
  box-sizing: border-box;
}

/* The story's own price. No words beside it — the column heading has already
   said whose price it is — so it sits against the right edge where money
   belongs. */
.tl-keepsake-base {
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid #dcdcdc;
  text-align: right;
}

.tl-keepsake-base .tl-keepsake-row-price {
  font-size: 20px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Options table ---------------------------------------------------------- */

.tl-keepsake-table-scroll {
  overflow-x: auto;
}

.tl-keepsake-qty-col {
  width: 1%;
  white-space: nowrap;
}

.tl-keepsake-label-col {
  text-align: left;
}

.tl-keepsake-table {
  width: 100%;
  border-collapse: collapse;
}

/* Same cell metrics as .tl-pricing-table on the photo page, so both builders
   have identically proportioned tables. Header text style is left to the
   theme, exactly as the photo page leaves it. */
.tl-keepsake-table th,
.tl-keepsake-table td {
  padding: 12px 10px;
  border-bottom: 1px solid #ddd;
  vertical-align: middle;
}

.tl-keepsake-table th {
  text-align: left;
  white-space: nowrap;
}

.tl-keepsake-table tr:last-child td {
  border-bottom: 0;
}

/* A header above a form field needs extra left padding to sit over the text
   INSIDE that field rather than over the field's outer edge: the cell's own
   10px, plus the control's 1px border and 12px inner padding = 23px. Columns
   holding plain text (Price) need no such offset. */
.tl-keepsake-table th.tl-keepsake-field-col {
  padding-left: 23px;
}

/* Heading and amount are both centred, so the figures stay directly under the
   word above them. The th needs the extra class in its selector to outrank
   ".tl-keepsake-table th", which would otherwise left-align this header. */
.tl-keepsake-price-col,
.tl-keepsake-table th.tl-keepsake-price-col {
  text-align: center;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/**
 * One gift, banded against the next.
 *
 * Every row of one keepsake shares a background, and consecutive gifts
 * alternate, so a page and its labels read as one thing. Without it several
 * keepsakes ran together as a single long list with nothing to say where one
 * ended and the next began.
 */
.tl-keepsake-table tbody tr.tl-keepsake-group-shaded > td {
  background: #e4ece7;
}

/* A gift starts at its own Keepsake's Title heading, so that is where the rule
   goes — not at the title box, which is one row further down. */
.tl-keepsake-table tbody tr.tl-keepsake-title-heading-row > td {
  border-top: 1px solid #c6d5cc;
}

.tl-keepsake-table tbody tr.tl-keepsake-title-heading-row:first-child > td {
  border-top: 0;
}

/* Both of a gift's headings read the same, since they do the same job. */
.tl-keepsake-section-heading,
.tl-keepsake-labels-heading {
  display: block;
  font-weight: 700;
}

.tl-keepsake-title-heading-row > td {
  padding-top: 14px;
  padding-bottom: 2px;
}

/**
 * A story page's labels: the heading that introduces them, then one row each
 * with the stepper first and the label it belongs to beside it — the same
 * reading order as a line in the cart.
 */
.tl-keepsake-labels-heading-row td {
  padding-top: 14px;
  padding-bottom: 2px;
}

.tl-keepsake-labels-heading {
  display: block;
  font-weight: 700;
}

.tl-keepsake-labels-note {
  display: block;
  color: #555;
  font-size: 0.9em;
}

/* Story title note spacing: in step 1 the title box follows the note straight
   away, so it needs room under it. Spacing only - the look is the same note. */
.tl-keepsake-title-panel .tl-keepsake-labels-note {
  margin-bottom: 10px;
}

/* Label picture beside step 2's note. Flex rather than a float so the sentence
   forms its own column and cannot wrap back under the picture, and so nothing
   can overlap the table below. Step 1's note has no picture. */
.tl-keepsake-options .tl-keepsake-labels-note {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  /* The note used to be two lines of text sitting straight on the label list.
     With an 85px picture in it, that same zero gap reads as the label rows
     touching the image, so it gets the same 10px step 1's note has. */
  margin-bottom: 10px;
}

/* 85px, not the 32 an icon would take: the merchant's size, settled by eye so
   the "My Story" caption printed under the code still reads as words. */
.tl-keepsake-note-image {
  flex: 0 0 auto;
  width: 85px;
  height: 85px;
}

.tl-keepsake-label-cell {
  display: flex;
  align-items: center;
  gap: 12px;
}

.tl-keepsake-label-name {
  color: #333;
}

/**
 * Choosing the one label type a story comes with.
 *
 * Only on the BUILDER's table (.tl-keepsake-table-pick). The reorder screen
 * keeps its Type / Quantity / Price columns and its steppers — that is where
 * several types and larger quantities are bought, and it shares the cell
 * metrics above, so nothing here may reach it.
 *
 * The <label> wraps the whole row's content, so a customer can press anywhere
 * along the name rather than having to hit an 18px circle.
 */
.tl-keepsake-pick {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0;
  cursor: pointer;
  /* The theme sets its own weight on form labels; this is a row of choices,
     not a field caption. */
  font-weight: inherit;
}

.tl-keepsake-pick-input {
  width: 18px;
  height: 18px;
  flex: none;
  margin: 0;
  cursor: pointer;
  /* The site's own green, so the chosen row matches the buttons that act on
     it rather than the browser's default blue. */
  accent-color: #2e8b57;
}

/* The chosen type carries a little more weight, so the answer reads at a
   glance and not only from the dot. */
.tl-keepsake-pick-input:checked ~ .tl-keepsake-label-name {
  font-weight: 700;
  color: #222;
}

.tl-keepsake-pick-input:focus-visible {
  outline: 2px solid #1a5fa8;
  outline-offset: 2px;
}

/* The whole row is the target, so the whole row answers to the pointer. Stated
   after the group-shading rule above and at the same weight, so it wins the
   tie on a shaded story. */
.tl-keepsake-table-pick tbody tr:hover > td {
  background: #e9efeb;
}

/* Remove: a quiet control until hovered, so it never competes with the fields
   beside it, but is always there for a keepsake the customer changes their
   mind about. */
/**
 * Delete, at the foot of the gift it removes.
 *
 * Worded and underlined rather than a bare × beside the price, which sat next
 * to the money and read as though it might remove that instead of the gift.
 */
.tl-keepsake-delete-row > td {
  padding-bottom: 14px;
}

.tl-keepsake-app .tl-keepsake-delete {
  border: 0;
  background: none;
  padding: 0;
  font-size: 0.9em;
  font-family: inherit;
  color: #8a2b23;
  text-decoration: underline;
  cursor: pointer;
}

.tl-keepsake-app .tl-keepsake-delete:hover,
.tl-keepsake-app .tl-keepsake-delete:focus {
  color: #c0392b;
}

.tl-keepsake-row-price {
  font-weight: 600;
}

.tl-keepsake-title-cell {
  min-width: 220px;
}

/* Inherit the theme's face and size so the title a customer types reads at the
   same size as the table around it, matching the photo page. Scoped under
   .tl-keepsake-app so the padding here beats the theme's own input rule. */
.tl-keepsake-app .tl-keepsake-title {
  width: 100%;
  box-sizing: border-box;
  border: 1px solid #ccc;
  border-radius: 6px;
  padding: 10px 12px;
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
  background-color: #fff;
  color: #111;
}

.tl-keepsake-title:focus {
  outline: 2px solid #2e8b57;
  outline-offset: 1px;
}

/* Counter and its hint share a line under the field. */
.tl-keepsake-title-note {
  display: block;
  margin-top: 5px;
}

.tl-keepsake-counter {
  font-size: 16px;
  color: #888;
  font-variant-numeric: tabular-nums;
}

/* Inside the title cell the hint sits beside the counter rather than under
   it, so it does not add a third line to every row. */
.tl-keepsake-title-note .tl-keepsake-help {
  display: inline;
  margin-top: 0;
  margin-left: 10px;
}

.tl-keepsake-counter-full {
  color: #a8541b;
  font-weight: 600;
}

/* Summary ---------------------------------------------------------------- */

/* The story leads, its labels follow: same line shape, the story a little
   heavier, so the eye groups them without a second heading. */
.tl-keepsake-summary-story {
  font-weight: 600;
  padding-bottom: 8px;
  border-bottom: 1px dotted #cfcfcf;
}

.tl-keepsake-summary-label {
  color: #555;
}

/* Same metrics as .tl-summary-line on the photo page, and deliberately no
   font rules, so both summaries inherit the theme identically. */
.tl-keepsake-summary-line {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 8px;
}

.tl-keepsake-summary-line span {
  flex: 1;
}

.tl-keepsake-summary-line strong {
  text-align: right;
  white-space: nowrap;
  min-width: 70px;
}

/* The photo page never needs this: it has one story title for the whole
   order. Here every line is a different story page, so without its name two
   pages ordering the same labels would look like duplicates. */
.tl-keepsake-summary-page {
  display: block;
  font-weight: 700;
}

/**
 * The word and the figure sit together at the right-hand edge.
 *
 * They were pushed to opposite ends of the panel, which at 550px left the
 * label stranded a long way from the number it names — the eye had to travel
 * the width of the column to pair them up. The AMOUNT keeps the right edge,
 * because that is the edge every figure on this page lines up on; the label
 * moves across to meet it.
 */
.tl-keepsake-subtotal {
  display: flex;
  justify-content: flex-end;
  align-items: baseline;
  gap: 16px;
  margin-top: 16px;
  padding-top: 12px;
  border-top: 1px solid #ddd;
  font-size: 18px;
  font-weight: 600;
}

/**
 * Delete, in the same column as Proceed to Cart and Save for Later and wearing
 * the same clothes: filled grey while there is nothing to delete, filled green
 * once the story has a title.
 *
 * Grey here means NOT READY, not disabled. The button stays clickable and says
 * what is missing when pressed, which is this site's convention on both
 * builders — a disabled button cannot explain itself.
 */
/**
 * Cancel, and Delete this keepsake.
 *
 * The builder renders this as a <button>, which centres its own text; the
 * reorder screen renders it as an <a>, which does not — so on that screen the
 * word sat against the left edge of a full-width button while every other
 * button on the page was centred. Both are stated here rather than relying on
 * the element, and the underline goes with it: this is a button, whichever tag
 * it happens to be built from.
 */
.tl-keepsake-delete-button {
  display: block;
  width: 100%;
  box-sizing: border-box;
  padding: 12px 20px;
  border: 0;
  border-radius: 6px;
  background: #d8d8d8;
  color: #777;
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
  line-height: 1.4;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
}

.tl-keepsake-delete-button:hover,
.tl-keepsake-delete-button:focus {
  text-decoration: none;
}

.tl-keepsake-delete-button:not(.tl-not-ready) {
  background: #2e8b57;
  color: #fff;
}

.tl-keepsake-delete-button:not(.tl-not-ready):hover,
.tl-keepsake-delete-button:not(.tl-not-ready):focus {
  background: #25754a;
}

.tl-keepsake-actions {
  margin-top: 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* Matches the photo page's button states: grey until ready, green when it
   can actually be used. */
.tl-keepsake-app .tl-checkout-button {
  padding: 12px 20px;
  border: 0;
  border-radius: 6px;
  font-size: 16px;
  font-weight: 600;
  background: #d8d8d8;
  color: #777;
}

.tl-keepsake-app .tl-checkout-button:disabled {
  cursor: not-allowed;
}

.tl-keepsake-app .tl-checkout-button:not(:disabled):not(.tl-not-ready) {
  background: #2e8b57;
  color: #fff;
  cursor: pointer;
}

.tl-keepsake-app .tl-checkout-button:not(:disabled):not(.tl-not-ready):hover {
  background: #25754a;
}

.tl-keepsake-save-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.tl-keepsake-save-intro {
  margin: 0;
}

.tl-keepsake-app .tl-keepsake-save-input {
  width: 100%;
  box-sizing: border-box;
  border: 1px solid #ccc;
  border-radius: 6px;
  padding: 10px 12px;
  font-family: inherit;
  font-size: inherit;
  background: #fff;
  color: #111;
}

.tl-keepsake-app .tl-keepsake-save-submit {
  padding: 12px 20px;
  border: 0;
  border-radius: 6px;
  font-size: 16px;
  font-weight: 600;
  background: #2e8b57;
  color: #fff;
  cursor: pointer;
}

.tl-keepsake-app .tl-keepsake-save-submit:hover {
  background: #25754a;
}

.tl-keepsake-save-message {
  margin: 0;
  color: #2e8b57;
}


/* Reorder: one column, since there is no summary panel to sit beside. */
.tl-keepsake-body--single {
  grid-template-columns: minmax(0, 1fr);
  max-width: 900px;
}

/* Charged once for the project, so it sits between the labels and the total
   rather than inside the table. */
/* Setup and handling, directly above the Total on the reorder screen. It
   follows the Total to the right-hand edge: they are two money lines stacked
   one on the other, and leaving this one spread across the panel while the
   Total bunched at the right made a pair that no longer looked like a pair. */
.tl-keepsake-fee-line {
  display: flex;
  justify-content: flex-end;
  align-items: baseline;
  gap: 16px;
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid #eee;
  color: #555;
}

.tl-keepsake-previous {
  display: inline-block;
  margin-left: 10px;
  padding: 2px 8px;
  border-radius: 999px;
  background: #eef5f0;
  border: 1px solid #cfe0d6;
  font-size: 13px;
  color: #2e6b4f;
  vertical-align: middle;
}

/* Narrow screens: the photo page has no breakpoints and simply overflows.
   Stacking here costs nothing on desktop and matches the agreed layout. */
@media (max-width: 900px) {
  .tl-keepsake-body {
    grid-template-columns: minmax(0, 1fr);
    padding: 20px;
  }

  .tl-keepsake-app .tl-app-header {
    padding: 20px 20px 0;
  }

  .tl-keepsake-notice {
    margin-left: 20px;
    margin-right: 20px;
  }
}

/* Below the width the three columns need, they stack in their numbered order
   rather than being squeezed: 1, then 2, then the total. */
@media (max-width: 1560px) {
  .tl-keepsake-body {
    grid-template-columns: minmax(0, 1fr);
  }
}
