/* ==========================================================================
   BLOOM — the visual direction
   ==========================================================================
   Loaded after styles.css, so it wins on equal specificity without needing
   !important anywhere. Kept as its own file so the whole look can be pulled
   out by deleting one <link>.

   Three rules hold it together:

     1. Surfaces are tinted, not outlined. A 1px grey border round everything
        made the app read as a spreadsheet. Soft fills and a brand-tinted
        shadow separate things without drawing a box around them.

     2. Colour means something. Pink is the brand moment. Traffic light is
        status and nothing else. The six category hues label a category and
        never a state. Blue is structure. Nothing is coloured for decoration
        except the countdown ring, which has earned it.

     3. Two densities, one language. The couple's portal is generous, the
        planner side is tight — same fonts, same colours, same components.
   ========================================================================== */


/* ---------- foundations --------------------------------------------------- */

html, body {
  background: var(--surface);
  font-family: var(--sans);
  font-size: 15.5px;
  letter-spacing: -.006em;
}


/* ---------- app chrome ---------------------------------------------------- */

.topbar {
  padding: 13px 26px;
  border-bottom: 1px solid var(--line-soft);
  background: var(--surface);
}

.wordmark {
  font-family: var(--display);
  font-size: .93rem;
  font-weight: 800;
  letter-spacing: -.02em;
  text-transform: none;
  color: var(--pink);
}

.biz-name { color: var(--ink-faint); font-size: .85rem; }

.modnav {
  gap: 4px;
  padding: 0 22px;
  border-bottom: 1px solid var(--line-soft);
}

/* Tabs read as soft pills rather than underlines — the single change that
   most stops the app looking like an admin panel. */
.modnav-item,
.subnav-item {
  padding: 8px 15px;
  border: none;
  border-radius: var(--radius-pill);
  background: none;
  color: var(--ink-soft);
  font-family: var(--sans);
  font-size: .89rem;
  font-weight: 600;
  letter-spacing: -.01em;
  cursor: pointer;
  transition: background .15s ease, color .15s ease;
}

.modnav-item:hover,
.subnav-item:hover { background: var(--surface-soft); color: var(--ink); }

.modnav-item.is-active,
.subnav-item.is-active {
  border-bottom-color: transparent;
  background: var(--pink-tint);
  color: var(--pink-deep);
}

.subnav {
  gap: 4px;
  padding-bottom: 9px;
  border-bottom: 1px solid var(--line-soft);
}


/* ---------- buttons ------------------------------------------------------- */

.btn {
  padding: 9px 17px;
  border-radius: var(--radius-pill);
  font-family: var(--sans);
  font-size: .875rem;
  font-weight: 600;
  letter-spacing: -.01em;
  transition: transform .12s ease, box-shadow .15s ease,
              background .15s ease, border-color .15s ease;
}

.btn:active { transform: translateY(1px); }

/* --btn-pink, not --pink. bloom.css loads AFTER styles.css, so this rule wins
   — which is exactly how the fix in styles.css looked like it had done
   nothing. Same trap as the missing .comment-file CSS on 29 Aug: check the
   cascade before believing a change did not land. */
.btn-primary {
  border: none;
  background: var(--btn-pink);
  color: #fff;
  box-shadow: 0 2px 8px rgba(232, 25, 122, .26);
}

.btn-primary:hover {
  background: var(--pink-deep);
  box-shadow: 0 4px 14px rgba(232, 25, 122, .32);
}

/* THE THREE TIERS HAVE TO LOOK LIKE THREE TIERS. 16 September.
   Gee, on the budget line card: the attach and open buttons "don't look like
   they were meant to be more prominent".

   Measured, and it was never 400 separate mistakes. styles.css designed the
   secondary button TEAL and readable — see its own rule near line 416. This
   file loads AFTER it, re-declared the same class as grey-on-white, and so
   that teal has never once been on screen. Grey-outline secondary and
   borderless ghost then sit a hairline apart, and at btn-sm they read as the
   same button, so the eye has nothing to land on anywhere in the app.

   170 btn-sm, 92 ghost, 82 secondary, 55 primary across index.html and 25
   modules — and NOT ONE of them needed touching. One rule, every screen.

   Teal deliberately, not pink: pink is the single filled primary — the one
   thing on a screen you press hardest — and a second pink tier would put two
   loudest things side by side. Teal is already the app's second voice.

   AND THE HOVER MOVED WITH IT. It used to go pink on hover, which on a teal
   outline is two brand colours fighting inside one button. */
.btn-secondary {
  border: 1.5px solid var(--teal);
  background: var(--surface);
  color: var(--teal-deep);
  font-weight: 700;
}

.btn-secondary:hover {
  background: var(--teal-tint);
  border-color: var(--teal-deep);
  color: var(--teal-deep);
}

/* Ghost drops a step to stay clear of the new secondary. It is the tier for
   Delete, Cancel, Save-a-copy — present, findable, never competing. */
.btn-ghost { border: none; background: none; color: var(--ink-faint); font-weight: 500; }
.btn-ghost:hover { background: var(--surface-soft); color: var(--ink); }

.btn-sm { padding: 6px 13px; font-size: .81rem; }

.btn:focus-visible,
.modnav-item:focus-visible,
.subnav-item:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--pink);
  outline-offset: 2px;
}


/* ---------- inputs -------------------------------------------------------- */

input[type="text"], input[type="email"], input[type="tel"], input[type="url"],
input[type="date"], input[type="time"], input[type="number"], input[type="search"],
input[type="password"], select, textarea {
  padding: 9px 13px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font-family: var(--sans);
  font-size: .89rem;
  transition: border-color .15s ease, box-shadow .15s ease;
}

input:focus, select:focus, textarea:focus {
  border-color: var(--pink);
  box-shadow: 0 0 0 3px var(--pink-tint);
  outline: none;
}


/* ---------- cards --------------------------------------------------------- */

/* No border, no coloured top rail — a soft fill and a warm shadow. */
/* A border, after all. "No border, no coloured top rail" was the old rule and
   it left every card floating — Gee, 30 Aug: "with no border around them, it
   looks a bit funny." A hairline for the ordinary ones; the wedding cards
   below take a heavier one in their own colour. */
.card, .ov-card, .wedding-card {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
}

.ov-card { padding: 20px 22px; border-top: none; }

.ov-card h3 {
  margin-bottom: 10px;
  color: var(--ink-faint);
  font-family: var(--sans);
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .11em;
  text-transform: uppercase;
}

.ov-big {
  font-family: var(--display);
  font-size: 2.1rem;
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -.035em;
}

.ov-sub { color: var(--ink-soft); font-size: .84rem; }

/* ---------------------------------------------------------------------------
   "NEXT UP" — what replaced "95 things still open". 15 September.

   Gee: *"I don't want the couple to have a list when they first jump on the
   overview to say 95 things still open, because that's going to overwhelm
   them."*

   ⚠️ AND THE NUMBER WAS NOT JUST LOUD, IT WAS WRONG ABOUT WHOSE IT WAS. Most
   of those 95 are HER tasks — booking suppliers, chasing invoices — and a
   couple reads the figure as ninety-five things they personally owe.

   Deliberately NOT styled like `.ov-big`: this tile no longer leads with a
   figure, so borrowing the big-number treatment for a list would make three
   task titles shout. Small label, readable items, dates aligned right.
   --------------------------------------------------------------------------- */

.ov-next-label {
  margin-bottom: 7px;
  color: var(--ink-faint);
  font-size: .68rem;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
}

.ov-next {
  margin: 0 0 8px;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 7px;
}

.ov-next li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.ov-next-what {
  font-size: .9rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--ink);
}

.ov-next-when {
  flex: 0 0 auto;
  font-size: .74rem;
  font-weight: 700;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.ov-next-when.is-overdue { color: #b3001b; }

.ov-next-late { color: #b3001b; font-size: .78rem; font-weight: 700; }

.ov-next-none { color: var(--ink-soft); font-size: .9rem; }

/* Gee, 30 Aug: "I really want the boxes to really stand out because, with no
   border around them, it looks a bit funny."

   She is right, and the fix is not just a line: a 2px border in the card's own
   colour plus a tint falling away from the top, so the card reads as an object
   rather than as text floating on paper. */
.wedding-card {
  padding: 20px 22px;
  border: 2px solid #ffc2dc;
  background: linear-gradient(180deg, #fff5f9 0%, var(--surface) 62%);
  transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease;
}

.wedding-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-lg);
  border-color: var(--v-magenta, #e8197a);
}

/* ---------- a celebrancy project reads differently at a glance -------------
   Gee, 29 Aug: "I want a different box colour so I can differentiate that
   it's a celebrant client."

   A wash and a left rail rather than a loud fill: the cards sit in one grid
   with the weddings, so this has to be legible without shouting over the
   status pill or the countdown. Sage, because pink is the brand and amber
   already means overdue.
   --------------------------------------------------------------------------- */

/* A celebrancy project is a different KIND of thing, not a variant of the
   same one — so the whole card changes, not a stripe down one edge. Mint, the
   colour that means celebrancy everywhere else in the app. */
.wedding-card.is-celebrancy {
  border-color: #8fe6d8;
  background: linear-gradient(180deg, #f0fdfa 0%, var(--surface) 62%);
}

.wedding-card.is-celebrancy:hover { border-color: var(--v-mint, #00bfa5); }

.wedding-card.is-celebrancy .card-name { color: var(--c-teal, #00695c); }

/* Filled, where a status pill is outlined. Two shapes, so what something IS
   can never be mistaken for what STATE it is in. */
.celebrancy-pill {
  margin-left: 6px;
  border: 1px solid var(--v-mint, #00bfa5);
  background: var(--v-mint, #00bfa5);
  color: #fff;
}

.card-name {
  font-family: var(--display);
  font-size: 1.15rem;
  font-weight: 700;
  letter-spacing: -.025em;
}


/* ---------- category colour -----------------------------------------------
   Applied as .cat-1 … .cat-6, hashed from the category name in JS so
   "Beauty" is the same hue every time the page opens.                       */

.cat-1 { --cat: var(--c-teal);   --cat-tint: var(--c-teal-tint);   }
.cat-2 { --cat: var(--c-sky);    --cat-tint: var(--c-sky-tint);    }
.cat-3 { --cat: var(--c-indigo); --cat-tint: var(--c-indigo-tint); }
.cat-4 { --cat: var(--c-plum);   --cat-tint: var(--c-plum-tint);   }
.cat-5 { --cat: var(--c-peach);  --cat-tint: var(--c-peach-tint);  }
.cat-6 { --cat: var(--c-sage);   --cat-tint: var(--c-sage-tint);   }

.cat-chip {
  display: inline-block;
  padding: 3px 11px;
  border-radius: var(--radius-pill);
  background: var(--cat-tint, var(--surface-soft));
  color: var(--cat, var(--ink-soft));
  font-size: .71rem;
  font-weight: 700;
  letter-spacing: .02em;
}


/* ---------- tables -------------------------------------------------------- */

.bg-table, .sup-table, .pay-table { font-size: .87rem; }

.bg-table thead th,
.sup-table thead th,
.pay-table thead th {
  padding: 9px 12px;
  border-bottom: 1px solid var(--line);
  color: var(--ink-faint);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .11em;
  text-transform: uppercase;
}

/* One navy for every category heading.
   The six hues were tried here and read as noise: a budget is one list of
   money, and colouring each section differently made it look like six lists.
   Navy for the headings, pink for the totals — structure and brand, nothing
   competing. The hues still do their job elsewhere, where a category is being
   picked out of a mixed set rather than heading its own block. */
.bg-table tr.bg-cat th {
  padding-top: 22px;
  border-bottom: 2px solid var(--blue);
  color: var(--blue);
  font-family: var(--display);
  font-size: .82rem;
  font-weight: 800;
  letter-spacing: .06em;
  text-transform: uppercase;
}

/* "The same as the top, but just the pink" — her words. The band takes exactly
   the padding an ordinary row takes, so the only thing separating it from the
   lines above is the colour. */
.bg-table tr.bg-subtotal td {
  padding-top: 9px;
  padding-bottom: 9px;
  border-bottom: none;
  background: var(--pink-tint);
  color: var(--pink-deep);
  font-weight: 700;
}

/* Round the ends so the subtotal band reads as one object. */
.bg-table tr.bg-subtotal td:first-child { border-radius: var(--radius-sm) 0 0 var(--radius-sm); }
.bg-table tr.bg-subtotal td:last-child  { border-radius: 0 var(--radius-sm) var(--radius-sm) 0; }

.bg-table tbody tr:hover td { background: var(--surface-soft); }
.bg-table tr.bg-subtotal:hover td { background: var(--pink-tint); }

.num { font-variant-numeric: tabular-nums; }


/* ---------- status pills: traffic light, meaning unchanged ---------------- */

.status, .pill {
  border-radius: var(--radius-pill);
  font-size: .71rem;
  font-weight: 700;
  letter-spacing: .01em;
}


/* ---------- tasks and run sheet ------------------------------------------- */

.task-row {
  border: none;
  border-bottom: 1px solid var(--line-soft);
  border-radius: var(--radius-sm);
}

.task-row:hover { background: var(--surface-soft); }

/* The whole row opens the task now, so it has to say so. Only the pointer —
   an eighty-row list where every row lit up would flicker as you scrolled. */
.task-row.is-clickable { cursor: pointer; }
.task-row.is-clickable a,
.task-row.is-clickable input,
.task-row.is-clickable button,
.task-row.is-clickable .row-edit { cursor: default; }
.task-row.is-clickable a,
.task-row.is-clickable button { cursor: pointer; }
/* 🛑 700, AND THE RULE THAT DECIDES THIS LIVES HERE, NOT IN styles.css.
   Gee, 17 September, after the run sheet went bold: "is that site-wide as
   well?" She chose every list name.

   ⚠️ `.task-title` IS DECLARED IN BOTH FILES AT THE SAME SPECIFICITY, and
   bloom.css loads AFTER styles.css, so this line is the one that wins. Setting
   the weight in styles.css instead would have changed nothing at all and
   looked like the feature simply did not work — `specificity-ties-go-to-the-
   later-file`, which this project has already been caught by once. */
.task-title { font-size: .93rem; font-weight: 700; }

.task-group-head {
  color: var(--blue);
  font-family: var(--display);
  font-size: .78rem;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
}

.tl-row { border-radius: var(--radius-sm); }
.tl-time { font-variant-numeric: tabular-nums; font-weight: 600; }


/* ---------- empty states, toasts, modals ---------------------------------- */

.empty {
  padding: 44px 22px;
  border: none;
  border-radius: var(--radius);
  background: var(--surface-soft);
  color: var(--ink-soft);
  text-align: center;
}

.toast { border-radius: var(--radius-pill); box-shadow: var(--shadow-lg); font-weight: 600; }

.modal-box { border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); }

.modal-head h2 {
  font-family: var(--display);
  font-size: 1.2rem;
  letter-spacing: -.025em;
}


/* ==========================================================================
   The couple's portal — the generous density
   ========================================================================== */

.portal-topbar { border-bottom: none; }

/* Contain the full-bleed hero below. 100vw counts the vertical scrollbar, so
   the hero is a few pixels wider than the page and the body scrolls sideways.
   `clip` rather than `hidden` because `hidden` on an ancestor silently kills
   position:sticky — which the budget's status column depends on. */
#portal-view { overflow-x: clip; }

/* Logo, names, date and countdown as one composed block rather than four
   things stacked. This is the screen a bride screenshots. */
/* Full-bleed: the wrap is centred and capped, so pulling out by its padding
   isn't enough — the gradient has to escape to the viewport edges or it reads
   as a panel with hard corners floating in white. */
.portal-head {
  margin: 0 calc(50% - 50vw) 30px;
  padding: 44px 26px 38px;
  width: 100vw;
  background: radial-gradient(120% 100% at 50% 0%,
              #fde9f2 0%, #fdf4f8 55%, #ffffff 100%);
  text-align: center;
}

/* Height-constrained with automatic width, so a wide wordmark stays a wide
   wordmark. Forcing a logo into a square is what makes software look like it
   was handed the brand rather than built around it. */
.portal-head-logo {
  display: block;
  width: auto;
  max-width: 240px;
  height: 56px;
  margin: 0 auto 18px;
  object-fit: contain;
}

.portal-head h1 {
  color: var(--ink);
  font-family: var(--display);
  font-size: clamp(1.7rem, 5vw, 2.5rem);
  font-weight: 800;
  letter-spacing: -.04em;
}

.portal-date {
  margin-top: 6px;
  color: var(--pink-deep);
  font-size: .9rem;
  font-weight: 600;
}

/* The countdown ring — the one deliberately decorative thing in the product,
   on the one screen where delight is the job. */
.portal-ring {
  display: grid;
  place-items: center;
  width: 128px;
  height: 128px;
  margin: 22px auto 0;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 5px 22px rgba(232, 25, 122, .17);
}

.portal-ring b {
  color: var(--pink);
  font-family: var(--display);
  font-size: 2.6rem;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.05em;
}

.portal-ring span { color: var(--ink-soft); font-size: .74rem; font-weight: 600; }

#portal-view .subnav {
  justify-content: center;
  margin-bottom: 26px;
  border-bottom: none;
}

/* Portal cards sit on tint rather than white. That single swap is what
   separates the couple's density from yours, without changing a component. */
#portal-view .ov-card { background: var(--surface-soft); box-shadow: none; }
#portal-view .ov-card.is-teal { background: var(--teal-tint); }
#portal-view .ov-card.is-pink { background: var(--pink-tint); }

.portal-hint {
  border-left: none;
  border-radius: var(--radius);
  background: var(--teal-tint);
  color: var(--teal-deep);
}

.portal-supplier,
.portal-note,
.access-row {
  border: none;
  border-radius: var(--radius);
  background: var(--surface-soft);
}

.portal-supplier-name { font-family: var(--display); letter-spacing: -.02em; }

.portal-summary > div {
  border: none;
  border-radius: var(--radius);
  background: var(--surface-soft);
}

.portal-summary strong {
  font-family: var(--display);
  font-size: 1.35rem;
  font-weight: 800;
  letter-spacing: -.035em;
}

#portal-view .task-row:hover { background: var(--surface-warm); }


/* ---------- settings ------------------------------------------------------ */

.set-block { border-bottom: 1px solid var(--line-soft); }

.set-block h2 {
  font-family: var(--display);
  font-size: 1.15rem;
  letter-spacing: -.025em;
}

/* A settings block that folds. The <summary> carries the h2, so the heading
   still reads as a heading — it just becomes the control as well.
   ⚠️ `display: flex` KILLS THE DEFAULT TRIANGLE in Chrome, which is why the
   arrow is drawn here instead: without it there is nothing saying the heading
   can be pressed, and a control you have to be told about is not a control. */
.set-fold > summary {
  display: flex;
  align-items: center;
  gap: .5rem;
  cursor: pointer;
  list-style: none;
  border-radius: 8px;
  padding: .15rem .35rem;
  margin-inline: -.35rem;
}
.set-fold > summary::-webkit-details-marker { display: none; }
.set-fold > summary h2 { margin: 0; }

.set-fold > summary::before {
  content: "▾";
  font-size: .8em;
  color: var(--ink-faint, #a0949a);
  transition: transform .12s ease;
}
.set-fold:not([open]) > summary::before { transform: rotate(-90deg); }

.set-fold > summary:hover { background: var(--ground-soft, rgba(0,0,0,.035)); }
.set-fold > summary:focus-visible { outline: 2px solid var(--calm, #007c85); outline-offset: 2px; }

/* Says what pressing it does, so the arrow is not the only hint. */
.set-fold > summary::after {
  content: "Hide";
  margin-left: auto;
  font-family: var(--sans);
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--ink-faint, #a0949a);
}
.set-fold:not([open]) > summary::after { content: "Show"; }


@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    transition-duration: .001ms !important;
  }
}

/* ---------------------------------------------------------------------------
   THE CLOCK ON A TIME BOX — and it lives here, not in styles.css.

   Every time field in the app becomes a plain text box at boot, so Gee sees
   "9:30 am" rather than 09:30. That fixed the army time she asked about twice
   and quietly removed the PICKER, because a text box has none. Clicking one
   did nothing, and the only clue left was faint placeholder text.

   Kadija, 1 Sept, on a supplier's team times: "I couldn't change their times.
   It didn't show the options, so I don't know how to do this part." The field
   worked. It did not look like it did.

   ⚠️ WHY IT IS IN THIS FILE. The rule above — the one setting `padding` and
   `background` shorthands on every input — is in bloom.css, which loads AFTER
   styles.css. `input[data-loose-time="1"]` is an attribute selector, so it
   carries exactly the same specificity as `input[type="text"]`. Same
   specificity means the later SHEET wins, whatever position it holds inside
   its own file. I put this at the very end of styles.css first and it still
   lost; the page itself said so when asked which rules matched.

   No !important. It just has to be in the last sheet that touches inputs.

   The clock is drawn INSIDE the box rather than as a button beside it: twelve
   of these sit in twelve different layouts, and a new sibling element in each
   is twelve chances to break one. A background image cannot disturb a layout,
   and the whole box becomes the target.
   --------------------------------------------------------------------------- */
input[data-loose-time="1"] {
  padding-right: 30px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236c6067' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 7v5l3 2'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 9px center;
  cursor: pointer;
}

/* ---------------------------------------------------------------------------
   THE COUPLE'S TASK ROW — one way in, and a ⋮ for the rest.

   Gee, 2 Sept: "Shouldn't it be in a comment file or add your answer?
   Shouldn't that all be in one, and then the reminder shouldn't that be in
   the dots?" Kadija reached the same complaint independently.

   The row carried three <details> side by side — Add your answer · Add a
   comment or a file · Remind me. Three decisions on every row before doing
   anything, across eighty-three tasks.

   The answer and the comments still exist and are still separate — an answer
   is one editable thing with a Save, a comment is an append-only thread. What
   changed is that the row now shows a SUMMARY rather than three invitations,
   and the reminder moved behind the same ⋮ the planner's side uses.
   --------------------------------------------------------------------------- */

/* What the row tells you without opening anything: how many comments, and
   when the next nudge is. */
.task-sum {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 2px;
}

.task-sum-bit {
  font-size: .78rem;
  color: var(--ink-faint);
  white-space: nowrap;
}

/* The dots sit after the due date, at the end of the row. Quiet until wanted,
   like every other one in the app. */
.task-row > .row-dots { align-self: center; flex: 0 0 auto; }

/* Reminder shortcuts — the same four the planner's own panel offers, so a
   couple is not left counting back from the 18th in their head. */
.remind-opts {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin: 8px 0 4px;
}

.remind-opt {
  padding: 4px 11px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill, 999px);
  background: var(--surface);
  color: var(--ink-soft);
  font: inherit;
  font-size: .78rem;
  line-height: 1.2;
  cursor: pointer;
}

.remind-opt:hover { border-color: var(--teal); color: var(--teal-deep); }

.remind-opt.is-on {
  background: var(--teal-deep);
  border-color: var(--teal-deep);
  color: #fff;
  font-weight: 600;
}

@media (hover: none) {
  .remind-opt { padding: 7px 13px; font-size: .84rem; }
}

/* The reminder block keeps its markup but loses its chip. It is opened by the
   ⋮, not by a third link on the row — that link is the one Gee and Kadija both
   asked to be rid of. When it is open it takes the full width like the other
   two, so the summary being hidden costs nothing.

   ⚠️ Do NOT "tidy" this by removing reminderHtml() from the row. That was the
   first attempt and it left the couple with no way to set or clear a reminder
   at all, while the row still showed one from the data. */
.portal-remind > summary { display: none; }
.portal-remind[open] { flex: 1 0 100%; margin-top: 4px; }

/* The × on the payments block. Gee, 2 Sept: "upcoming payments, you can't
   clear that from the screen." Quiet, in the corner, and never louder than the
   amounts it sits beside. */
.pay-due-head { position: relative; }

/* The way back, once the payments block is hidden. Deliberately quiet — it is
   a line saying something exists, not the thing itself. Same shape and same
   words as the findings panel's put-aside line, because it is the same idea.
   Before this existed, Hide was a one-way door. */
/* 🛑 IT LOOKS LIKE THE BLOCK IT REPLACES. Gee, on her phone: *"the part where
   you've got Hide in that little yellowy box should probably be a red box with
   the upcoming payments."*

   She is right, and I had it backwards. I made it a dashed outline with no
   fill — quiet, on the reasoning that it is only a line saying something
   exists. But this is MONEY, and the thing behind it is the reddest block on
   their screen. A washed-out dashed box says "a setting"; the same tint and
   the same edge say "your payments are in here".

   ⚠️ SAME TOKENS AS `.pay-due` ITSELF — --warn-tint, --warn-mid and the 3px
   --warn edge — so hidden and shown read as one component in two states
   rather than two different things. */
.pay-due-back {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 0 0 18px;
  padding: 10px 14px;
  border: 1px solid var(--warn-mid);
  border-left: 3px solid var(--warn);
  border-radius: 12px;
  background: var(--warn-tint);
  font-size: .84rem;
  /* 🛑 700, BECAUSE SHE ASKED AND BECAUSE THE RULE ALREADY SAYS SO.
     Gee: *"The payments coming up 11 hidden should be bolded."* `the-name-of-
     the-thing-is-bold` is a standing rule here — the name of the thing is 700
     and never lighter than the metadata beside it. This line IS the name of
     what is hidden, and it was sitting at 600 beside an 800 button. */
  font-weight: 700;
  /* On the tint, --ink-soft drops to 4.1:1. --ink is 12.9:1 and this is the
     line that has to be readable at arm's length on a phone. */
  color: var(--ink);
}

.pay-due-back button {
  flex: 0 0 auto;
  min-height: 32px;
  padding: 5px 10px;
  border: 0;
  border-radius: 7px;
  background: none;
  font-family: inherit;
  font-size: .72rem;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  /* --danger on the page ground, measured: 6.4:1. Same red as the Hide it
     replaces, so the pair reads as one control in two states. */
  color: var(--danger);
  cursor: pointer;
}
.pay-due-back button:hover { background: rgba(0,0,0,.06); }
.pay-due-back button:focus-visible { outline: 2px solid var(--danger); outline-offset: 2px; }

@media (hover: none) { .pay-due-back button { min-height: 44px; padding: 8px 12px; } }

/* 🛑 A WORD, NOT A GLYPH, AND AT FULL OPACITY. 18 September.
   It was a × at `opacity: .55` whose only explanation was a `title` — and a
   title needs hover, which a phone does not have. Gee asked what it did,
   which is the whole answer about whether it was clear.

   ⚠️ THE COLOUR IS MEASURED, NOT PICKED. `--warn` (#d4121f) on `--warn-tint`
   (#ffe3e4) is **4.45:1** at FULL opacity — already under the 4.5 this size
   needs, and at .55 it was nowhere near. `--danger` (#b3001b) is **5.92:1**
   on the same tint and is already this app's overdue red, so it is the colour
   the app had for this all along.

   ⚠️ SAME SHAPE AS THE FINDINGS PANEL'S "HIDE" — uppercase, 800, tracked —
   because it is the same action and one action must have one name. */
.pay-due-hide {
  position: absolute;
  top: -3px;
  right: -4px;
  min-height: 26px;
  padding: 4px 7px;
  border: 0;
  border-radius: 8px;
  background: none;
  color: var(--danger);
  font-family: inherit;
  font-size: .72rem;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  line-height: 1;
  cursor: pointer;
}
.pay-due-hide:hover { background: rgba(0,0,0,.06); }
.pay-due-hide:focus-visible { outline: 2px solid var(--danger); outline-offset: 2px; }

/* On a touch screen the target is the thing — 44px is the floor, and this is
   the device she found it on. */
@media (hover: none) {
  .pay-due-hide { min-height: 44px; padding: 6px 10px; }
}
@media print { .pay-due-hide { display: none !important; } }

/* ---------------------------------------------------------------------------
   THE COUPLE'S OWN CONTROLS, and headings that mean something.

   Gee, 2 Sept: "you don't have the same type of headings that we've got in our
   version for the checklist, with the blues and the meanings, and there's no
   way at the top to be able to hide the ticked-off, sort by due date or
   anything like that."

   Both were true. Her checklist has Hide completed and an order switch; the
   couple had neither, on a list of 85 across 13 sections. And her headings say
   what KIND of thing a section is — a meeting carries the grape rail and a
   badge, everything else her pink — while the couple's were one flat teal, so
   "Meeting 16 July" and "Two Months Before Wedding" looked identical.
   --------------------------------------------------------------------------- */

.portal-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 18px;
  margin: 0 0 20px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
}

.portal-tool-seg {
  display: inline-flex;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill, 999px);
  overflow: hidden;
}

.portal-tool {
  padding: 6px 14px;
  border: 0;
  background: none;
  color: var(--ink-soft);
  font: inherit;
  font-size: .82rem;
  cursor: pointer;
}
.portal-tool + .portal-tool { border-left: 1px solid var(--line); }
.portal-tool:hover { background: var(--surface-soft); color: var(--ink); }
.portal-tool.is-on { background: var(--teal-deep); color: #fff; font-weight: 600; }

.portal-tool-check {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: .84rem;
  color: var(--ink-soft);
  cursor: pointer;
}

@media (hover: none) {
  .portal-tool { padding: 9px 15px; font-size: .88rem; }
}

/* ---------------------------------------------------------------------------
   THE COUPLE'S HEADINGS ARE NOW GEE'S HEADINGS.

   Gee, 2 Sept, shown the two side by side: "I like the way my checklist is,
   so I'd like for it to be the same as mine. Same colours, same everything in
   the sense of the design."

   Her checklist draws a section as a BLOCK — tinted background, a 3px rail
   down the left, rounded on the right. The couple's were flat text with a
   hairline underneath, which is why a section did not read as a section.

   Values copied from styles.css:6982 (ordinary) and :6826 / :6916 (meeting),
   deliberately identical rather than "close":

     ordinary   sky   background --c-sky-tint     rail --c-sky
     meeting    grape background --c-indigo-tint  rail --c-indigo

   ⚠️ If either of those rules is ever restyled, restyle this with it. Two
   copies of one design is exactly how the two sides drifted apart in the
   first place.
   --------------------------------------------------------------------------- */
.portal-phase > .portal-phase-head {
  background: var(--c-sky-tint);
  border: 0;
  border-left: 3px solid var(--c-sky);
  border-radius: 0 8px 8px 0;
  padding: 11px 16px;
  margin: 0 0 10px;
  gap: 10px;
}

/* ⚠️ THE COUPLE'S FOLD, AND IT HAS TO BE A REAL TOUCH TARGET. They read this on
   a phone, so unlike the planner's 18px triangle this gets 28px of width and
   height — under that, a thumb hits the heading and nothing happens, which
   reads as a broken control rather than a missed tap.

   It takes the phase's own colour rather than a grey, because the heading it
   sits in is a coloured band and a grey glyph on a tinted ground reads as
   disabled. `currentColor` means it follows the meeting and attention variants
   below without one rule each. */
.portal-phase > .portal-phase-head .portal-phase-fold {
  flex: 0 0 auto;
  /* ⚠️ The heading is `align-items: baseline` (styles.css:7606), which would
     hang a 28px box off the text's baseline and sit it low. Centre it against
     the row instead. */
  align-self: center;
  width: 28px;
  height: 28px;
  margin: -4px 0 -4px -6px;
  border: 0;
  background: none;
  padding: 0;
  font-size: 12px;
  line-height: 1;
  color: currentColor;
  opacity: .75;
  cursor: pointer;
}
.portal-phase > .portal-phase-head .portal-phase-fold:hover,
.portal-phase > .portal-phase-head .portal-phase-fold:focus-visible { opacity: 1; }

/* The tasks go, the heading and its count stay — a shut phase still has to say
   "10 to go" rather than becoming a band with nothing in it. */
.portal-phase.is-folded > .task-list { display: none; }
.portal-phase.is-folded > .portal-phase-head { margin-bottom: 4px; }

.portal-phase > .portal-phase-head .portal-phase-name {
  color: var(--c-sky);
  font-size: .92rem;
  font-weight: 600;
  letter-spacing: .06em;
}

.portal-phase > .portal-phase-head .portal-phase-count {
  font-size: .78rem;
  color: var(--ink-faint);
  font-weight: 500;
}

/* A meeting is grape, exactly as it is on her side. */
.portal-phase.is-meeting > .portal-phase-head {
  background: var(--c-indigo-tint);
  border-left-color: var(--c-indigo);
}
.portal-phase.is-meeting > .portal-phase-head .portal-phase-name { color: var(--c-indigo); }

.portal-phase-kind {
  display: inline-block;
  padding: 3px 11px;
  border-radius: var(--radius-pill, 20px);
  background: var(--c-indigo);
  color: #fff;
  font-size: .64rem;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
}

/* "No date" is a real answer, not a leftover bin — but it is not one of Gee's
   phases either, so it stays quiet rather than borrowing their colour. */
.portal-phase.is-nodate > .portal-phase-head {
  background: var(--surface-soft);
  border-left-color: var(--line);
}
.portal-phase.is-nodate > .portal-phase-head .portal-phase-name { color: var(--ink-soft); }

/* Paper gets the words, not the blocks — same as her own checklist. */
@media print {
  .portal-phase > .portal-phase-head { background: none !important; }
  .portal-phase-kind { background: none !important; color: #2a2126 !important; font-weight: 800; }
}

/* ---------------------------------------------------------------------------
   ONE BOX. The answer lives inside the conversation now.

   Gee, 2 Sept: "I don't understand why we have two of them. I think that's
   silly." Kadija reported the same on her own — one of only four complaints
   both testers reached independently.

   The row used to offer "Add your answer" AND "Add a comment or a file" side
   by side, and the couple had to guess which one was meant. Now there is one
   way in; inside, the standing list sits above the talking about it.

   It is only drawn where a list already exists — most tasks are not asking for
   one, and an empty box on every task would be the second invitation again. */
.answer-standing {
  margin: 0 0 12px;
  padding: 12px 14px;
  border: 1px solid var(--c-sky, #0067a3);
  border-radius: 10px;
  background: var(--c-sky-tint, #daf0ff);
}

.answer-standing-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 10px;
  margin-bottom: 7px;
}

.answer-standing-label {
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--c-sky, #0067a3);
}

.answer-standing .answer-by { font-size: .74rem; color: var(--ink-soft); }
.answer-standing .answer-box { width: 100%; }

/* Hide your own comment. Only ever on your own — the × is not drawn on
   somebody else's words. Quiet, because it sits beside a name and a time and
   must not be the loudest thing in the thread. */
.comment-hide {
  margin-left: auto;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--ink-faint);
  font-size: .95rem;
  line-height: 1;
  cursor: pointer;
  opacity: .6;
}
.comment-hide:hover { opacity: 1; color: var(--late); background: var(--late-tint); }
.comment-hide:focus-visible { outline: 2px solid var(--late); outline-offset: 1px; opacity: 1; }

.comment-who { display: flex; align-items: baseline; gap: 8px; }

@media (hover: none) { .comment-hide { width: 30px; height: 30px; opacity: 1; } }
@media print { .comment-hide { display: none !important; } }

/* ---------------------------------------------------------------------------
   WHAT IS LATE, AT THE TOP.

   Measured before building: 8 overdue tasks spread across 13 sections, the
   first of them 1,266 pixels down. You scrolled past two screens before
   learning anything was late.

   A copy, not a move — the task keeps its place in its own section, and the
   note underneath says so. Same reasoning as the run sheet's arrival cards:
   "what is late" and "where does this belong" are different questions and both
   deserve an answer.
   --------------------------------------------------------------------------- */
.portal-attention {
  margin: 0 0 26px;
  padding: 16px 18px;
  border: 1px solid var(--late-tint, #ffe0e3);
  border-left: 3px solid var(--late, #b3001b);
  border-radius: 0 12px 12px 0;
  background: var(--surface);
}

.portal-attention-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 0 0 8px;
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.portal-attention-head.is-late { color: var(--late, #b3001b); }
.portal-attention-head.is-soon { color: var(--warn); margin-top: 18px; }

.portal-attention-count {
  padding: 1px 9px;
  border-radius: 20px;
  font-size: .72rem;
  font-weight: 700;
}
.is-late .portal-attention-count { background: var(--late-tint, #ffe0e3); color: var(--late, #b3001b); }
.is-soon .portal-attention-count { background: var(--warn-tint, #ffeeda); color: var(--warn); }

.portal-attention-note {
  margin: 12px 0 0;
  font-size: .78rem;
  color: var(--ink-faint);
}

/* The business name becomes a button only when there is somewhere to go.
   Somebody with one business sees exactly what they saw before — no new
   affordance for a choice that does not exist. */
.biz-name.is-switch {
  cursor: pointer;
  padding: 3px 9px;
  border-radius: var(--radius-pill, 999px);
  border: 1px solid transparent;
}
.biz-name.is-switch::after {
  content: ' \25BE';
  font-size: .7em;
  opacity: .7;
}
.biz-name.is-switch:hover {
  border-color: var(--line);
  background: var(--surface-soft);
  color: var(--ink);
}
.biz-name.is-switch:focus-visible {
  outline: 2px solid var(--pink);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------------
   OVERDUE, ABOVE EVERYTHING — on Gee's own checklist.

   Built for the couple first, where the first late task sat 1,266px down a
   page of 85. Her own list is bigger — 119 tasks, 13 overdue on Tiffany &
   Liam — with the same fault: sections are planning phases, so what is late is
   scattered through them.

   Red, not sky. Every other heading on this page is a section of the wedding;
   this one is a state of the wedding, and it must not read as another phase.
   --------------------------------------------------------------------------- */
.task-group.is-late-block > .task-group-head.is-late-head {
  background: var(--late-tint, #ffe0e3);
  border-left: 3px solid var(--late, #b3001b);
  border-radius: 0 8px 8px 0;
  padding: 11px 16px;
  font-size: .92rem;
  letter-spacing: .06em;
  gap: 10px;
  color: var(--late, #b3001b);
}

.task-group.is-late-block > .task-group-head.is-late-head .task-group-count {
  background: var(--late, #b3001b);
  color: #fff;
  padding: 1px 9px;
  border-radius: 20px;
  font-size: .74rem;
  font-weight: 700;
}

.late-block-note {
  margin: 8px 0 22px;
  font-size: .74rem;
  color: var(--ink-faint);
}

/* Not on paper. A printed run of the checklist is the document, and the same
   task appearing twice in it is a mistake rather than a feature. */
@media print { .task-group.is-late-block { display: none !important; } }

/* Arriving / Leaving on a team row. Sits under the place, because it is about
   that place — "at Crown Towers they're leaving". Quiet: on most rows the
   answer is Arriving and it should not shout. */
.team-dir {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 6px;
  font-size: .78rem;
  color: var(--ink-soft);
}
.team-dir select {
  padding: 4px 9px;
  font-size: .82rem;
}


/* ===========================================================================
   COMING UP — the landing page.

   Gee and Kadija, 2 September: "we want to be able to see a snapshot of what
   is to come with the couple so we can prepare and plan... The Aisle Planner
   bar on the right-hand side is so shit."

   Deliberately quiet. Nothing on this page competes with the one thing it is
   for, which is reading a list of names and dates at a glance. The only
   colour is on the tags and on anything late.
   =========================================================================== */

/* ⚠️ THE FIVE STAT TILES ARE DELETED. 11 September.
   .home-stats / .home-stat / .home-stat-split drew "7 BOOKED · 0 COMPLETE ·
   0 CANCELLED · 4 IN 2026 · 3 IN 2027" across the top. Two of the five were
   permanently zero and carried exactly as much weight as the one that was
   not. The masthead at the foot of this file replaces them; the one fact
   worth keeping — how many weddings, and in which years — is now the quiet
   line under the greeting. Deleted rather than parked: dead rules for a shape
   nothing emits are how the next person rebuilds the wrong thing. */

.home-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 7px;
  margin-bottom: 16px;
}

/* .home-bar-gap is deleted with the two-view switch — it was the spacer that
   held the view pills apart from the window pills, and there is one group of
   pills now. */

.home-pill {
  font: inherit;
  font-size: .8rem;
  font-weight: 600;
  padding: 5px 13px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-soft);
  cursor: pointer;
}

.home-pill:hover { border-color: var(--pink); color: var(--pink-deep); }

.home-pill.is-on {
  background: var(--btn-pink);
  border-color: var(--btn-pink);
  color: #fff;
}

.home-couple {
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
  margin-bottom: 12px;
}

.home-couple-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 10px;
  padding: 10px 15px;
  background: var(--surface-soft);
  border-bottom: 1px solid var(--line);
}

.home-couple-head .nm {
  font-family: var(--display);
  font-size: 1rem;
  font-weight: 700;
}

.home-couple-head .dt { font-size: .8rem; color: var(--ink-soft); }

.home-couple-head .cd {
  margin-left: auto;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--pink-deep);
  background: var(--pink-tint);
  padding: 3px 10px;
  border-radius: 999px;
}

.home-couple-head.is-late .nm { color: var(--danger); }
.home-couple-head.is-late .cd { color: var(--danger); background: var(--danger-tint); }

.home-line {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 9px 15px;
  border-top: 1px solid var(--line-soft);
  background: var(--surface);
  cursor: pointer;
}

.home-couple .home-line:first-of-type { border-top: none; }
.home-line:hover { background: var(--surface-soft); }
.home-line.is-late { background: var(--danger-tint); }

.home-box {
  flex: 0 0 auto;
  width: 17px;
  height: 17px;
  accent-color: var(--teal);
  cursor: pointer;
}

/* "They said" has nothing to tick — reading it is what closes it. The space is
   kept so every row on the page still lines up. */
.home-box.is-none { visibility: hidden; }

.home-tag {
  flex: 0 0 auto;
  min-width: 76px;
  text-align: center;
  font-size: .65rem;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 5px;
}

.home-tag.pay  { background: var(--danger-tint);   color: var(--danger); }
.home-tag.task { background: var(--pink-tint);     color: var(--pink-deep); }
.home-tag.said { background: var(--c-sage-tint);   color: var(--c-sage); }

.home-what {
  flex: 1 1 auto;
  min-width: 0;
  font-size: .9rem;
}

.home-what small {
  display: block;
  font-size: .76rem;
  color: var(--ink-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.home-when {
  flex: 0 0 auto;
  font-size: .79rem;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}

.home-when.is-late { color: var(--danger); font-weight: 700; }

.home-arrow { flex: 0 0 auto; color: var(--ink-faint); font-size: .95rem; }
.home-line:hover .home-arrow { color: var(--pink); }

.home-empty {
  border: 1px dashed var(--line);
  border-radius: 12px;
  padding: 40px 20px;
  text-align: center;
  color: var(--ink-soft);
}

.home-empty-big {
  font-family: var(--display);
  font-size: 1.2rem;
  font-weight: 700;
  color: var(--ink);
  margin: 0 0 6px;
}

/* On a phone the tag and the date are the first things to go — the couple's
   name and what the thing is are what you actually read. */
@media (max-width: 560px) {
  .home-tag { min-width: 0; padding: 3px 6px; font-size: .6rem; }
  .home-line { gap: 8px; padding: 9px 11px; }
  .home-arrow { display: none; }
}


/* ---------------------------------------------------------------------------
   The row's two controls, as the mock-up actually showed them.

   Gee, 2 September, looking at the proposal: "we don't like that the box in
   pink with the three dots is a heavy background. We'd rather it be lighter
   and more visible, so that we know that it is an edit button."

   Moving them left and turning up their opacity was only half of it — at rest
   .row-dots was a bare glyph on a transparent border, so beside the tick it
   still read as decoration rather than something you press. A filled chip says
   "this is on"; an outlined one says "press me".

   Nothing here touches .has-comments or .is-new — a live conversation and an
   unread one keep the fills they already have.
   -------------------------------------------------------------------------- */
.task-row > .row-dots,
.task-row > .comment-flag:not(.has-comments):not(.is-new) {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 7px;
  color: var(--ink-soft);
}

.task-row > .row-dots:hover,
.task-row > .row-dots[aria-expanded="true"],
.task-row > .comment-flag:not(.has-comments):not(.is-new):hover {
  background: var(--pink-tint);
  border-color: var(--pink);
  color: var(--pink-deep);
}


/* ===========================================================================
   THE COMMENT BADGE — option 5, chosen 2 September.

   Gee, on a call with Kadija: "where you've got the talking mark everywhere
   and the number one... we can't see that properly. It's not easily viewable.
   This is site-wide wherever you've got this. We're gonna miss shit."

   She was right twice over. The chip had no background and an 11px number,
   AND the bubble itself was the emoji 💬 — a picture with its own colours
   baked in, which ignores `color` completely. Every previous attempt to make
   unread stand out was styling a glyph that could not change. ui.js now hands
   every surface a drawn icon instead.

   Three states, and each says a different thing:

     nothing yet   outlined and quiet — a button to start a conversation
     a thread      filled teal — it exists, and you have read it
     unread        SOLID ORANGE, AND IT SAYS THE WORD: "2 new"

   Option 5 is the words one. A number alone has to be interpreted; "2 new"
   does not, and it still reads when the page is printed in black and white,
   which no colour ever does. The icon is hidden in that state so the words
   are the whole chip.

   Loads after styles.css, so these win at equal specificity.
   =========================================================================== */

.comment-flag {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 8px;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: var(--surface);
  color: var(--ink-soft);
  line-height: 1;
}

.comment-flag .cmt-ico { width: 14px; height: 14px; display: block; }

.comment-flag:hover {
  border-color: var(--pink);
  color: var(--pink-deep);
  opacity: 1;
}

/* A conversation you have already read. Present, not shouting. */
.comment-flag.has-comments {
  background: var(--teal-tint);
  border-color: var(--teal);
  color: var(--teal-deep);
  opacity: 1;
}

.comment-flag.has-comments span,
.comment-flag.has-comments .flag-badge {
  font-size: .72rem;
  font-weight: 700;
  background: none;
  color: inherit;
  padding: 0;
  border-radius: 0;
}

/* SOMEBODY IS WAITING.
   The unread chip is defined once, at the bottom of this file, under
   "OPTION A". The solid tangerine fill and the hidden bubble that used to sit
   here were rejected and have been deleted rather than overridden — a dead
   rule that still matches is how three things went wrong today. */
.comment-flag.is-new { opacity: 1; }

.comment-flag.is-new span,
.comment-flag.is-new .flag-badge,
.task-row .comment-flag.is-new span,
.task-row .comment-flag.is-new .flag-badge {
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .01em;
  background: none;
  color: #fff;
  padding: 0;
  border-radius: 0;
  white-space: nowrap;
}

/* The couple's side uses its own two elements for the same idea. Same icon,
   so it inherits a colour rather than fighting an emoji. */
.task-sum-bit .cmt-ico,
.bg-ask .cmt-ico { width: 13px; height: 13px; vertical-align: -2px; }


/* ===========================================================================
   TWO THINGS THAT SHIPPED WRONG ON 2 SEPTEMBER, AND WHY.

   Gee, seeing it live: "can you please look at this and tell me why this
   doesn't look like the option that you showed us... I cannot see this
   properly." She was looking at a tiny orange blob reading "ne".

   1. THE BADGE WAS STILL A CORNER DOT.
      Option 5 puts the words INSIDE the chip. But .flag-badge was built on
      1 September as an absolutely-positioned 16px circle pinned to the chip's
      top-right — and the new rules only changed its colours and font, never
      its position. So "2 new" was crammed into a 16px circle hanging off the
      edge and clipped to "ne". Worse: the icon is hidden in this state, so
      with the badge out of flow the chip had NO in-flow content at all and
      collapsed to its own padding.

      Putting it back in normal flow is the whole fix.

   2. THE ⋮ MENU NEVER GOT ITS OUTLINE.
      The rule was written `.task-row > .row-dots`. The dots are not a child of
      the row — they sit inside .row-gutter. So the selector matched nothing,
      silently, and the button stayed a bare glyph. A wrong selector does not
      warn; it just does nothing, which is why this needs measuring rather than
      reading.
   =========================================================================== */

/* 1 — the words sit in the chip. The last selector repeats the highest
   specificity already in styles.css so this actually wins. */
.comment-flag.is-new .flag-badge,
.task-row .comment-flag.is-new .flag-badge,
.task-row:not(.is-unread) .comment-flag.is-new .flag-badge {
  position: static;
  top: auto;
  right: auto;
  min-width: 0;
  height: auto;
  padding: 0;
  line-height: 1;
  text-align: left;
  box-shadow: none;
  background: none;
  color: #fff;
  font-size: .72rem;
  font-weight: 700;
  white-space: nowrap;
}

/* 2 — the real home of the ⋮ menu and the drag grip. */
.task-row .row-gutter .row-dots {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 24px;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: var(--surface);
  color: var(--ink-soft);
}

.task-row .row-gutter .row-dots:hover,
.task-row .row-gutter .row-dots[aria-expanded="true"] {
  background: var(--pink-tint);
  border-color: var(--pink);
  color: var(--pink-deep);
}

/* The grip is a handle, not a menu — same shape so the pair reads as one set
   of controls, lighter so the two ⋮ are not mistaken for each other. */
.task-row .row-gutter .row-mini.row-grip {
  width: 20px;
  height: 24px;
  border: 1px dashed var(--line);
  border-radius: 7px;
  background: none;
  color: var(--ink-faint);
}

.task-row .row-gutter .row-mini.row-grip:hover {
  border-style: solid;
  border-color: var(--teal);
  color: var(--teal-deep);
  background: var(--teal-tint);
}

.task-row .row-gutter { gap: 5px; }


/* ===========================================================================
   OPTION A — the unread chip. Chosen 2 September, and this is the last word
   on it. Everything above about "1 new", white ink and a solid tangerine fill
   was rejected on sight and is gone.

   Gee: "this is terrible. This is not the vibe that we're going for."

   She was right, and the reason is worth keeping: a SOLID fill made the chip a
   different kind of object from the teal one beside it. Two different objects
   down a column do not compare — the eye has to stop and read each one. Option
   A is the teal chip in another colour, nothing more. Pale tint, coloured
   edge, coloured text, identical size. The colour is the whole message.

   All five options were rendered inside the live app before being drawn, which
   is what today taught: designing against a blank page and posting a picture
   of it is how three versions in a row shipped looking nothing like the
   mock-up. The cascade has to be in the room.
   =========================================================================== */

/* The bubble stays in every state — it is what makes the chips the same size. */
.comment-flag.is-new .cmt-ico { display: block; }

.comment-flag.is-new,
.task-row .comment-flag.is-new,
.task-row > .comment-flag.is-new {
  background: var(--warn-tint);
  border-color: var(--warn);
  color: var(--warn);
  padding: 4px 8px;
  box-shadow: none;
}

.comment-flag.is-new:hover,
.task-row .comment-flag.is-new:hover {
  background: var(--warn);
  border-color: var(--warn);
  color: #fff;
}

.comment-flag.is-new span,
.comment-flag.is-new .flag-badge,
.task-row .comment-flag.is-new span,
.task-row .comment-flag.is-new .flag-badge,
.task-row:not(.is-unread) .comment-flag.is-new .flag-badge {
  color: var(--warn);
  font-size: .72rem;
  /* 700, exactly matching the read chip. At 800 the number came out three
     pixels wider and put a ragged edge back down the column. */
  font-weight: 700;
  box-shadow: none;
}

.comment-flag.is-new:hover span,
.comment-flag.is-new:hover .flag-badge { color: #fff; }

/* ---------------------------------------------------------------------------
   AND THE YELLOW ROW GOES.

   .task-row.is-unread washed the whole line in tint. That was chosen back when
   the badge itself was invisible and something had to carry the signal — so it
   was compensating for a bug rather than being a design. The chip does the job
   now, and the wash was fighting it: a pale orange chip on a pale yellow row
   is two weak signals instead of one clear one.

   The row keeps its normal background and its hover, like every other row.
   -------------------------------------------------------------------------- */
.task-row.is-unread { background: none; }
.task-row.is-unread:hover { background: var(--surface-soft); }


/* A crew's dietary line — full width under the driver row, because "no nuts"
   is a sentence and not a field. 77-dietary-per-team.sql. */
.team-diet {
  grid-column: 1 / -1;
  width: 100%;
  margin-top: 6px;
}


/* ---------------------------------------------------------------------------
   Moving a budget category up or down.

   Gee, 2 September: "there's no point in us having a $200 invoice on top when
   it's not even important."

   The arrows live in the category heading and stay out of the way until you
   are on it — a budget with twelve categories would otherwise open as
   twenty-four arrows. The order is contact_categories.sort_order, the same one
   the Contacts page uses, so a category cannot be third here and ninth there.
   -------------------------------------------------------------------------- */
.bg-cat-move {
  display: inline-flex;
  gap: 3px;
  margin-left: 8px;
  vertical-align: middle;
  opacity: 0;
  transition: opacity .12s ease;
}

.bg-cat:hover .bg-cat-move,
.bg-cat-move:focus-within { opacity: 1; }

.bg-cat-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 20px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink-soft);
  font-size: .75rem;
  line-height: 1;
  cursor: pointer;
}

.bg-cat-arrow:hover:not(:disabled) {
  border-color: var(--pink);
  background: var(--pink-tint);
  color: var(--pink-deep);
}

/* Shown, not hidden, at the ends of the list — a control that vanishes makes
   the row jump as you move down it. */
.bg-cat-arrow:disabled { opacity: .3; cursor: default; }


/* ---------------------------------------------------------------------------
   Category order, second pass.

   Gee, on the first version: "The buttons are very slow to be responsive in
   the budget with the moving of the categories, and there's no drag option."

   The slowness was not the saving — that already drew before it wrote. The
   arrows were HIDDEN until hover, and clicking one rewrites the table, which
   destroys the element being hovered. The new arrow arrives with no :hover on
   it, so it is invisible until the mouse moves, and moving a category three
   places meant click, jiggle, click, jiggle. They are visible at rest now.
   -------------------------------------------------------------------------- */
.bg-cat-move { opacity: .45; }
.bg-cat:hover .bg-cat-move,
.bg-cat-move:focus-within { opacity: 1; }

/* The whole heading is the drag handle; the grip says so. */
.bg-cat[draggable="true"] { cursor: grab; }
.bg-cat[draggable="true"]:active { cursor: grabbing; }

.bg-cat-grip {
  display: inline-block;
  margin-right: 7px;
  opacity: .35;
  font-size: .8rem;
  letter-spacing: -2px;
  vertical-align: middle;
}

.bg-cat:hover .bg-cat-grip { opacity: .7; }

.bg-cat.is-dragging { opacity: .45; }

/* ⚠️ THE LINE'S OWN GRIP — 10 Sept. The category headings have had a grip and
   arrows since 2 Sept and the lines inside them had NOTHING; Gee, 10 Sept: "I
   don't think I can move the line items inside the actual category. Which I
   might need to move things around."

   Deliberately the same ≡ at the same weight as .bg-cat-grip, sitting first in
   the cell so the two line up down the left edge and a line reads as nesting
   inside its category. It is a <button> rather than a styled span because only
   a focusable element is reachable without a mouse. */
.bg-line-grip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 22px;
  margin-right: 5px;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  opacity: 0;
  font-size: .8rem;
  letter-spacing: -2px;
  vertical-align: middle;
  cursor: grab;
  transition: opacity .12s ease;
}

/* Shown on the row under the cursor, the way the run sheet's gutter works —
   a handle on all twenty-nine lines at once reads as clutter. focus-within is
   not decoration: without it the grip is unreachable by keyboard, since there
   is no hover to trigger. */
.bg-table tbody tr:hover .bg-line-grip,
.bg-line-grip:focus-visible { opacity: .55; }
.bg-line-grip:hover { opacity: .9; }
.bg-line-grip:active { cursor: grabbing; }

/* No hover on a phone, so it stays put there — same rule the run sheet's
   gutter uses. */
@media (hover: none) {
  .bg-line-grip { opacity: .5; }
}

.bg-table tbody tr.is-dragging { opacity: .45; }

/* Where it will land. A line above the row, matching the category's own drop
   cue, so both reorders read the same way. */
.bg-table tbody tr.is-over > td {
  box-shadow: inset 0 3px 0 var(--pink);
}

/* Where it will land. A line above the row rather than a fill, so the heading's
   own category colour still reads underneath it. */
.bg-cat.is-over th {
  box-shadow: inset 0 3px 0 var(--pink);
}


/* An overdue count sits before the total, in the colour of the thing it is
   counting. Her session notes: "an overdue count shown per couple". */
.home-couple-head .cd.is-late {
  margin-left: auto;
  background: var(--danger-tint);
  color: var(--danger);
}
.home-couple-head .cd.is-late + .cd { margin-left: 6px; }

/* Where a link landed you. Gee, 2 Sept: a link should take you "to the page
   AND the section where that is linked". Scrolling there is half of it; saying
   WHICH one is the other half. It fades on its own — a row still lit an hour
   later is decoration, not an answer. */
.tl-row.is-found {
  animation: tl-found 4s ease-out;
  border-radius: var(--radius-sm);
}

@keyframes tl-found {
  0%, 55% { background: var(--warn-tint); box-shadow: inset 3px 0 0 var(--btn-tangerine); }
  100%    { background: none;             box-shadow: inset 3px 0 0 transparent; }
}

@media (prefers-reduced-motion: reduce) {
  .tl-row.is-found { animation: none; background: var(--warn-tint); }
}


/* ---------------------------------------------------------------------------
   Who is on site, from one crew.

   Gee, 2 September: "the number of suppliers on site, the number of dietary
   requirements. When I say four, then four dropdowns come through."
   80-crew-people.sql.
   -------------------------------------------------------------------------- */
.team-crew {
  grid-column: 1 / -1;
  margin-top: 8px;
  padding-top: 9px;
  border-top: 1px dashed var(--line);
}

.team-crew-count {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: .8rem;
  color: var(--ink-soft);
}

.team-crew-count input { width: 68px; }

.team-people { margin-top: 8px; display: grid; gap: 5px; }

.team-person {
  display: grid;
  grid-template-columns: 20px minmax(0, 1fr) minmax(0, 1.4fr);
  align-items: center;
  gap: 7px;
}

/* The number is the only thing telling you which of five people this is, so
   it stays legible rather than decorative. */
.team-person-n {
  font-size: .72rem;
  font-weight: 700;
  color: var(--ink-faint);
  text-align: right;
  font-variant-numeric: tabular-nums;
}

@media (max-width: 560px) {
  .team-person { grid-template-columns: 20px minmax(0, 1fr); }
  .team-person-n { grid-row: span 2; }
}


/* ---------------------------------------------------------------------------
   Titles that line up.

   Found by rendering three real rows side by side rather than by reading the
   CSS: the assignee pill sits BEFORE the title and its width follows the name,
   so "Unassigned" pushed one title ten pixels further right than "Kadija" did.
   Down a hundred rows that is a ragged left edge on the only column anybody
   actually reads.

   Fixed width with an ellipsis, not min-width: a long name would otherwise
   still shove its own row out of line, which is the same fault with extra
   steps.
   -------------------------------------------------------------------------- */
.task-row > .who-name {
  flex: 0 0 84px;
  max-width: 84px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: center;
}

/* Two of them on one row is rare and reads as one wide pill rather than two
   clipped ones. */
.task-row > .who-name + .who-name { flex-basis: auto; max-width: 84px; }

@media (max-width: 900px) {
  /* The name is the first thing to give way on a phone — the title is not. */
  .task-row > .who-name { flex-basis: 62px; max-width: 62px; }
}


/* The chip was the real culprit.
   Measured on three live rows: 54px with no comments, 76px with "2", 79px with
   an unread "1" — and it sits BEFORE the name, so every title started
   somewhere different. Fixing the name pill alone moved the problem without
   solving it, which is what measuring rather than assuming caught.
   One width for all three states, centred. */
.task-row > .comment-flag {
  width: 48px;
  justify-content: center;
}


/* ===========================================================================
   ONE PLACE FOR "ADD", ON ALL FOUR TABS.

   Gee, 2 September: "did you have a look at the whole website and all the
   differences in where the buttons are... what we have to do to make it
   synchronized?"

   Extracted every toolbar and compared them. Three tabs put + Add LAST, on the
   right, after Print and Export. The checklist puts it FIRST, on the left —
   the change Kadija asked for this morning, and she was right: adding is the
   thing done most often on any of these pages, and it was sitting past six
   other controls behind a row that wraps on a narrow screen.

   So the checklist was not the odd one out to be corrected. It was the one
   that had been fixed. These three now match it.

   Done with `order` rather than by moving the markup, deliberately: the budget
   tab's actions are fused into its summary block rather than a toolbar of
   their own, and re-cutting that markup to move one button is a far bigger
   risk than one line of CSS that can be deleted.
   =========================================================================== */

#add-budget-line,
#add-timeline-event,
#add-supplier { order: -1; }


/* The schedule-doesn't-match warning, loud enough to be seen.

   Her session notes, §4: "the mismatch-error message is too small/easy to
   miss — needs a more prominent alert style." It was one line of red text at
   the end of a sentence of totals, which is exactly where the eye stops
   reading. It is its own block now, with the colour doing the work rather
   than a font weight. */
.pay-mismatch {
  display: block;
  margin-top: 8px;
  padding: 9px 12px;
  border: 1px solid var(--danger);
  border-left: 3px solid var(--danger);
  border-radius: var(--radius-sm);
  background: var(--danger-tint);
  color: var(--danger);
  font-size: .85rem;
  font-weight: 600;
}

/* Money reads as money in the schedule too — right-aligned and tabular, so a
   column of amounts lines up on the decimal rather than wandering. */
.pay-table input[data-money] {
  text-align: right;
  font-variant-numeric: tabular-nums;
}


/* ---------------------------------------------------------------------------
   Who to ring on the day.

   Her session notes, §6. Read standing in a car park at 6am, so: big enough
   to hit with a thumb, a tel: link on every number, and nobody listed who has
   no number to give.

   Prints. This is the block that goes in the folder.
   -------------------------------------------------------------------------- */
.tl-phones {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  margin-bottom: 14px;
  overflow: hidden;
}

.tl-phones-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 14px;
  background: var(--c-sky-tint, #daf0ff);
  color: var(--c-sky, #0067a3);
  font-family: var(--display);
  font-size: .74rem;
  font-weight: 800;
  letter-spacing: .09em;
  text-transform: uppercase;
}

/* Hide / Show for the phone list. Pushed to the right so the heading still
   reads as a heading, and sized as a real target rather than a caption — the
   17px badge taught that lesson the hard way. */
/* Filled, for the same reason as .arr-card-hide: an outlined pill in the bar's
   own colour is technically visible and practically invisible. Fixed here in
   the same breath rather than waiting for her to report the second one. */
.tl-phones-hide {
  margin-left: auto;
  padding: 4px 12px;
  border: 1.5px solid currentColor;
  border-radius: 999px;
  background: #fff;
  color: var(--c-sky, #0067a3);
  font-family: inherit;
  font-size: .68rem;
  font-weight: 800;
  letter-spacing: .07em;
  text-transform: uppercase;
  cursor: pointer;
}

.tl-phones-hide:hover { background: var(--c-sky, #0067a3); color: #fff; }

/* Folded: the heading stays so she can find it again. */
.tl-phones.is-shut .tl-phone-list { display: none; }

.tl-phone-list { list-style: none; margin: 0; padding: 0; }

.tl-phone-list li {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  border-top: 1px solid var(--line-soft);
  font-size: .87rem;
}

.tl-phone-list li:first-child { border-top: none; }

.ph-who  { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ph-role { color: var(--ink-faint); font-size: .78rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* A phone number is the one thing on this block anybody presses. */
.ph-num {
  justify-self: end;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--c-sky, #0067a3);
  text-decoration: none;
  padding: 4px 9px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  white-space: nowrap;
}

.ph-num:hover { border-color: var(--c-sky, #0067a3); background: var(--c-sky-tint, #daf0ff); }

@media (max-width: 560px) {
  .tl-phone-list li { grid-template-columns: minmax(0, 1fr) auto; }
  .ph-role { grid-column: 1; grid-row: 2; }
}

@media print {
  .tl-phones { break-inside: avoid; }
  .ph-num { border: none; padding: 0; color: #000; }
}


/* ---------------------------------------------------------------------------
   A category's share of the budget. 82-category-percentages.sql.

   Kadija: "should we set a percentage, like in Aisle Planner, that will be
   allocated to the categories?" It sits on the SUBTOTAL row, next to the money
   it is being compared against — a target on the heading would be a number
   with nothing beside it to judge against.
   -------------------------------------------------------------------------- */
/* ⚠️ NOWRAP, AND THAT IS THE WHOLE FIX.
   Gee, 8 Sept, on the BEAUTY band: "why is this beauty line so long? That's
   ridiculous that the pink is so big… The padding is too much. It should be
   less, just straight, the same as the top, but just the pink."
   Her read of the symptom was right and the cause was not padding. This cell
   spans the last 7 of the table's 13 columns, and with `flex-wrap: wrap` the
   share box, the % and "no share set" did not fit that width — so they went
   onto a SECOND LINE inside the row and the pink band came out roughly twice
   the height of an ordinary one.
   It is one row of the table; it should read as one line. */
.bg-pct-cell {
  display: flex;
  align-items: center;
  gap: 9px;
  flex-wrap: nowrap;
  min-width: 0;
  font-size: .78rem;
  color: var(--ink-soft);
}

/* With nothing allowed to wrap, the words are what must give — never the box
   you type in, and never the bar. Truncated with an ellipsis rather than
   overflowing the cell, and the full text stays in the title attribute. */
.bg-pct-cell > .bg-pct-none,
.bg-pct-cell > .bg-pct-target,
.bg-pct-cell > .bg-pct-state {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bg-pct-wrap { display: inline-flex; align-items: center; gap: 2px; }

.bg-pct {
  width: 44px;
  padding: 3px 5px;
  text-align: right;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
  font: inherit;
  font-variant-numeric: tabular-nums;
}

.bg-pct:focus { border-color: var(--pink); outline: none; box-shadow: 0 0 0 3px var(--pink-tint); }
.bg-pct-sign  { color: var(--ink-faint); font-weight: 600; }
.bg-pct-none  { color: var(--ink-faint); font-style: italic; }
.bg-pct-target { font-variant-numeric: tabular-nums; }

/* Capped at 100% width so an overspend fills the bar rather than bursting it —
   the number beside it says by how much, which a 340%-wide bar cannot. */
.bg-pct-bar {
  flex: 0 0 90px;
  height: 5px;
  border-radius: 3px;
  background: var(--line);
  overflow: hidden;
}

.bg-pct-bar i { display: block; height: 100%; background: var(--teal); }
.bg-pct-state { font-weight: 600; color: var(--teal-deep); }
.bg-pct-state.is-over { color: var(--danger); }

/* The bar turns with the number, so colour and words never disagree. */
.bg-pct-cell:has(.is-over) .bg-pct-bar i { background: var(--danger); }

@media print { .bg-pct-cell { display: none; } }


/* ---------------------------------------------------------------------------
   Coming up, capped.

   Her session notes, §3: "Needs visual compression — too much whitespace
   between couple name and due-date column currently."

   The gap on a LINE was never the problem — measured at 17px. The problem is
   the container: on a wide monitor a couple's name sits at the far left and
   its count is flung to the far right with a thousand pixels of nothing
   between them, and your eye has to travel the whole way to pair them up.

   Capping the width is the fix rather than restyling the rows. It is the same
   reason a newspaper sets in columns: past roughly 100 characters the eye
   loses the line it is on, and every row here is a name that has to be read
   against a date.

   Left-aligned rather than centred — it sits under a left-aligned page
   heading, and centring it would leave the board floating away from its own
   title.

   ⚠️ AND THE CAP IS DELETED, 11 September. The bands are full-bleed by
   design — reaching the edge of .wrap is what makes a couple's colour read as
   a section of the page rather than a wide card — so a cap here would leave
   them poking 26px out of an 1080px column and looking like a mistake. The
   reasoning above still holds for TEXT, which is why the masthead keeps a
   measure of its own (.hm-say, 58ch) and a row's text column is bounded by
   the band's grid rather than by the page.
   -------------------------------------------------------------------------- */

/* The couple's name and its counts belong to each other, so the counts stop
   at a sensible distance instead of hugging the far edge. */
@media (min-width: 1120px) {
  .home-couple-head .cd.is-late { margin-left: 18px; }
  .home-couple-head .dt { margin-right: auto; }
}


/* ===========================================================================
   COMING UP — the layout pass. 2 September, after looking at it properly.

   Gee, on the Zoom and again after: the way it is laid out is terrible. Her
   session notes, §3: "still described as 'doesn't look right' visually
   multiple times" and "needs visual compression — too much whitespace between
   couple name and due-date column."

   I capped the board at 1080px earlier and called it done. Rendering it at a
   size I could actually judge shows that was not enough: the text ended around
   400px and the date sat at 1080, so the eye crossed six hundred pixels of
   nothing to pair a task with its date. A cap that still leaves a gulf is not
   compression.

   Four changes, all pulling the same way — put what belongs together, together.
   =========================================================================== */

/* 1 · ⚠️ THE 860px MEASURE IS DELETED, 11 September, for the same reason the
   1080px one above it is: the bands are full-bleed and a cap here made them
   hang off the side of a narrow column. The measure now lives on the text
   that needs it rather than on the whole page. */

/* 2 · The tag stops shouting. It was 76px of fixed width in bold uppercase,
   competing with the thing it labels. It only has to be recognisable at a
   glance — the colour already does most of that work. */
.home-tag {
  min-width: 0;
  padding: 2px 7px;
  font-size: .6rem;
  letter-spacing: .04em;
  font-weight: 700;
}

/* 3 · Tighter rows. Twelve things due should be one screen, not two. */
.home-line { padding: 7px 13px; gap: 9px; }
.home-what small { margin-top: 1px; }
.home-couple-head { padding: 8px 13px; }
.home-couple { margin-bottom: 9px; }

/* 4 · ⚠️ THE STAT TILES ARE DELETED, 11 September. See the note where the
   block itself used to be, further up this file. */


/* ===========================================================================
   COMING UP — two piles, and cards behind a toggle. 2 September.

   Gee: "I don't love this whatsoever... This is very overwhelming, very
   confusing." She was right, and the cure was not arrangement. The old board
   showed everything all the time in rows that all looked equally important —
   tag, tick, name, couple, date, arrow on EVERY line. Eight things due became
   forty pieces of information with nowhere for the eye to land.

   So: one question per page, and four things gone from every row.
   =========================================================================== */

/* ⚠️ THE TWO COLUMNS ARE DELETED. 11 September.
   .home-piles / .home-col drew "Needs you now" beside "Coming up". Gee chose
   one page on 11 Sept and it is the bands at the foot of this file, so these
   are gone rather than left behind a toggle nobody opens. The two things that
   layout knew are kept in home.js, not here: anything WAITING counts as
   needing you now even with no date, and late sorts above everything else
   inside a couple. See sortForCouple(). */

/* ---- one row ---- */
.home-row {
  display: grid;
  grid-template-columns: 18px 78px minmax(0, 1fr);
  align-items: baseline;
  gap: 10px;
  padding: 9px 0;
  border-top: 1px solid var(--line-soft);
  cursor: pointer;
}

.home-row:first-of-type { border-top: 0; }
.home-row:hover { background: var(--surface-soft); }


.home-when { font-size: .76rem; color: var(--ink-faint); font-variant-numeric: tabular-nums; white-space: nowrap; }
.home-when.is-late { color: var(--danger); font-weight: 700; }

.home-t { font-size: .91rem; display: block; }
.home-text small { display: block; font-size: .77rem; color: var(--ink-faint); margin-top: 1px; }

/* THE TICK IS THERE, AND OUT OF THE WAY. Ticking from the board was asked for
   and kept; twelve empty boxes down the left of a page was the problem. */
.home-tick {
  width: 16px; height: 16px; margin: 0;
  accent-color: var(--teal);
  opacity: 0;
  transition: opacity .12s ease;
}

.home-row:hover .home-tick,
.home-tick:focus-visible,
.home-tick:checked { opacity: 1; }
.home-tick.is-none { visibility: hidden; }

/* ⚠️ THE COUPLE CARDS ARE DELETED — all 300 lines of them. 11 September.

   .cu-cards / .cu-card / .cc-nm / .cc-meta / .cc-flag / .cc-more were the
   two-column grid of tinted, outlined cards. They are replaced by the bands
   at the foot of this file, which Gee chose out of ten drawn options.

   Every lesson those rules carried is carried forward there, and each one was
   a real correction at the time — worth reading before anyone reaches for a
   card again:

   · the hue is the couple's identity and must never go red, so overdue stays
     the only warm thing on the page (3 Sept);
   · a pastel FILL says whose it is across the whole shape, where a 1.5px
     outline could not (3 Sept);
   · the tick gets a column of its own and stays visible — it was absolutely
     positioned on top of the date, which is the "problem with the five days
     overdue and the button that comes up" (3 Sept);
   · "+N more" takes the couple's hue rather than brand pink, which read as a
     second alert on a cool pastel (3 Sept);
   · the divider between rows has to be the white wash, because the warm
     near-white line is invisible on a cool pastel (3 Sept).

   The bands keep all five. What they do not keep is the red "N overdue" flag
   on the header: six of seven cards wore it, so it had stopped meaning
   anything at all. */


/* ===========================================================================
   Options to choose from — quote comparisons above the budget table
   ---------------------------------------------------------------------------
   Gee, 9 Sept: "we want a comparison one so they can see what we're giving
   them comparison-wise." Tiles, not rows: the whole point is reading three
   quotes ACROSS rather than down, and a table would put them in a column and
   make you scroll to compare two numbers.

   ⚠️ IT MUST NOT LOOK LIKE THE BUDGET. Nothing in here counts towards a single
   figure on this page, and the surest way to have three florist quotes read as
   $12,000 of florist is to draw them in the same white rows as the money. So:
   its own warm ground, its own border, and a heading that says what it is.
   =========================================================================== */
.cmp-panel {
  margin: 0 0 18px;
  padding: 16px 18px 18px;
  background: var(--surface-warm);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.cmp-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.cmp-head h3 { margin: 0; font-size: 1.02rem; }
.cmp-head #cmp-add { margin-left: auto; }
.cmp-intro { margin: 0; color: var(--ink-soft); font-size: .88rem; max-width: 62ch; }

.cmp-card {
  margin-top: 14px;
  padding: 12px 14px 14px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
/* Settled ones stay readable rather than disappearing — she may want to see
   what she chose and what she chose against. */
.cmp-card.is-settled { opacity: .72; }

.cmp-card-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.cmp-card-head h4 { margin: 0; font-size: .98rem; }
.cmp-card-head .spacer { flex: 1 1 auto; }

.cmp-flag {
  font-size: .74rem;
  padding: 2px 9px;
  border-radius: var(--radius-pill);
  white-space: nowrap;
}
.cmp-flag.is-waiting { background: var(--warn-tint); color: var(--warn); }
.cmp-flag.is-picked  { background: var(--pink-tint); color: var(--pink-deep); }
.cmp-flag.is-settled { background: var(--ok-tint);   color: var(--ok); }

/* WHO CAN SEE THIS, from migration 96.

   "Only you" is the one that has to be unmissable. A comparison she is still
   assembling — three suppliers, six quotes, half of them going in the bin —
   must never be mistaken for something the couple are looking at. So it is a
   solid dark chip rather than a tint: at a glance down a page of comparisons,
   the private ones are the ones that stand out.

   "Couple can see this" is deliberately the quiet one. It is the normal
   finished state, and a page of loud green badges saying "working correctly"
   is a page nobody reads. */
.cmp-flag.is-private {
  background: var(--ink);
  color: #fff;
}

.cmp-flag.is-shown {
  background: transparent;
  color: var(--ink-faint);
  border: 1px solid var(--line);
  font-weight: 500;
}


/* ---------- rate cards (migration 97) --------------------------------------
   What a supplier charges, drawn inside their contact card. Deliberately
   plainer than the comparison panel: this is Gee's own reference material and
   nobody else ever sees it, so it is a table to scan rather than something to
   present. */

/* Opens on top of the contact card, which is already at z-index 100. Not an
   openModal() modal — that closes whatever is open, and closing the contact
   form underneath would throw away the edit she is in the middle of. */
.modal.is-stacked { z-index: 140; }

.rate-card {
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 11px 13px;
  margin-bottom: 10px;
  background: var(--surface);
}

/* Past the date printed on it. Not an error — a price list simply expires —
   so it is a soft amber edge rather than anything alarming. */
.rate-card.is-stale { border-left: 3px solid var(--warn, #b26b00); }

.rate-card-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
}

.rate-card-name { font-weight: 700; }

.rate-card-sum {
  color: var(--ink-soft);
  font-size: .85rem;
  flex: 1 1 100%;
  order: 3;
}

.rate-until { color: var(--ink-faint); font-size: .78rem; font-weight: 500; }
.rate-stale { color: var(--warn, #b26b00); font-size: .78rem; font-weight: 700; }

/* ⚠️ SIZED UP, 15 SEPTEMBER, AND THE NUMBERS ARE WHY.
   Gee, reading her own What-they-need panel: *"that view that you had before,
   it's way too small, way, way, way too small. It's not visible. We need to
   make that better visually."*

   Measured on her screen before the change, in a panel 1,084px WIDE:
       column headers   10.23px
       row text         13.80px
       tick boxes       15 x 15px
       Keep button      12.55px

   Ten-pixel headers and a fifteen-pixel tick target is a form you squint at.
   The width was never the problem — the type was set for a narrow card and the
   panel grew around it.

   ⚠️ BOTH TABLES MOVE TOGETHER, DELIBERATELY. What they CHARGE and what they
   NEED share these classes on purpose — supplierneeds.js's header says they
   are two halves of one thing and giving either its own look would read as a
   second feature. They are equally unreadable, so they are equally fixed. */
.rate-table { width: 100%; border-collapse: collapse; margin: 9px 0 4px; font-size: 1.02rem; }

.rate-table th {
  text-align: left;
  font-size: .82rem;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--teal-deep);
  font-weight: 800;
  padding: 10px 10px;
  border-bottom: 2px solid var(--teal, #009faa);
}

.rate-table td {
  padding: 13px 10px;
  border-bottom: 1px solid var(--line);
  line-height: 1.5;
  color: var(--ink, #2a2126);
}

/* ⚠️ BUMPED TWICE, AND THE SECOND TIME IS THE POINT.
   The first pass took headers 10.2 → 11.8px and rows 13.8 → 14.7px. Gee looked
   again: *"I can't see that properly. You need to make that larger, bolder,
   easier to read, maybe a different colour, because it's very hard to
   understand."*

   Asking twice means the increment was the mistake, not the number. This is a
   step, not a nudge — and it takes her other two words seriously as well:
   BOLDER (the requirement itself is now 600 weight in full ink, not grey body
   text) and a DIFFERENT COLOUR (the source line is the one thing on the row
   that is NOT the requirement, so it drops back to faint and small while the
   wording comes forward).

   The failure before was that the wording and "from Pardesay Kakar Contract
   signed .pdf" were the same size and nearly the same colour, so the eye had
   to separate them by reading. */
.rate-table td .muted-note,
.rate-proposed td .muted-note {
  display: block;
  margin-top: 3px;
  font-size: .78rem;
  color: var(--ink-faint);
}

/* The requirement itself — the thing she is deciding about. */
.rate-proposed td:first-of-type,
.rate-proposed .sugg-what { font-weight: 600; }

/* A tick you have to aim at is a tick that gets missed. 15px was below every
   guideline there is; 20 with room around it is a target. */
.rate-table input[type="checkbox"],
.rate-proposed input[type="checkbox"] {
  width: 20px;
  height: 20px;
  accent-color: var(--teal-deep, #00695c);
  cursor: pointer;
}

/* The hours box is the one thing on this panel she is meant to CHANGE before
   keeping — it was 13.8px and easy to read straight past. */
.rate-table input[type="number"],
.rate-table input[type="text"],
.sugg-hours { font-size: .95rem; }

/* Prices line up or they cannot be compared, which is the entire job of this
   table. */
.rate-table .num { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; }

.rate-note { color: var(--ink-faint); font-size: .88rem; }

/* The separator between two links in a hint line. Without it "1 document" and
   the card link ran together into one phrase with a 0px gap. (That card link
   moved up beside the supplier's name on 1 October, as "Edit <supplier>".) */
.hint-sep { margin: 0 6px; color: var(--ink-faint); }
.rate-row-acts { text-align: right; white-space: nowrap; }

/* WHAT THE READER FOUND, AND HAS NOT SAVED.
   Tinted so it cannot be mistaken for the rows underneath that are real. */
.rate-proposed {
  background: var(--teal-tint, #e6f7f8);
  border: 1px dashed var(--teal);
  border-radius: 8px;
  padding: 10px 11px;
  margin: 10px 0;
}

/* The count and the Keep button, pinned to the top of the list.

   ⚠️ Gee's Classic Cars price list came back with TWENTY-EIGHT rows and the
   only Keep button was underneath all of them. From where she stood the reader
   had produced a long list and no way to act on it. Sticky, because unticking
   happens down the list and the number on the button is the feedback that a
   tick did something. */
.rate-proposed-bar {
  position: sticky;
  top: -1px;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  background: var(--teal-tint, #e6f7f8);
  margin: -10px -11px 4px;
  padding: 10px 11px 8px;
  border-bottom: 1px solid rgba(0, 0, 0, .06);
  font-size: .92rem;
}

/* ⚠️ SCOPED, NOT A CHANGE TO `.btn-sm`. Keep is the whole point of this panel
   and it computed to 12.55px — but `.btn-sm` is used across the entire app, so
   bumping it there would resize a hundred buttons nobody complained about. */
.rate-proposed-bar .btn-sm { padding: 8px 16px; font-size: .9rem; }

/* Tick all / untick all, and the running count, above the picker's list.
   Sticky for the same reason the Keep bar is: with 28 cars the control has to
   still be there when she is halfway down them. */
.rate-pick-bar {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: var(--surface);
  padding: 6px 2px 8px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 8px;
}

.rate-pick-count { font-size: .8rem; color: var(--ink-soft); font-variant-numeric: tabular-nums; }

.rate-proposed-head { margin: 0; font-size: .87rem; flex: 1 1 240px; }
.rate-proposed-act  { display: flex; align-items: center; gap: 12px; }
.rate-proposed .rate-table { margin-top: 4px; }

/* ---------------------------------------------------------------------------
   WHAT THEY NEED — migration 111. The list itself borrows `.rate-card` and
   `.rate-table` deliberately, so it reads as the other half of "what they
   charge" rather than a second feature. Only the add-row is new.

   Grid rather than flex: the four boxes want fixed proportions — a wide name,
   a narrow number, a basis, a note — and flex-basis on four children is the
   longer way to say the same thing. It collapses to one column on a phone,
   where four boxes across is unusable.
   --------------------------------------------------------------------------- */
.need-add {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) 72px minmax(0, 1.1fr) minmax(0, 1.4fr) auto;
  gap: 7px;
  align-items: center;
  margin-top: 8px;
}

/* The boxes are deliberately quieter than the app's standard input: this is a
   row you add to a list, not a form you fill in. */
.need-add input,
.need-add select {
  font: inherit;
  font-size: .86rem;
  padding: 6px 9px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm, 8px);
  background: var(--surface);
  color: var(--ink);
  min-width: 0;
}

.need-add input:focus-visible,
.need-add select:focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: 1px;
}

@media (max-width: 620px) {
  .need-add { grid-template-columns: minmax(0, 1fr); }
}

/* The two editable cells inside a suggestion row. The hours the reader pulled
   off "1 hour prior to event commencement" are a GUESS, so they arrive in a
   box she can correct rather than as text she has to trust. Sized to the
   content — a number box wide enough for a date is a number box that looks
   like it wants one. */
.sugg-hours,
.sugg-basis {
  font: inherit;
  font-size: .84rem;
  padding: 3px 6px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm, 8px);
  background: var(--surface);
  color: var(--ink);
  max-width: 100%;
}
.sugg-hours { width: 62px; text-align: right; font-variant-numeric: tabular-nums; }

.sugg-hours:focus-visible,
.sugg-basis:focus-visible { outline: 2px solid var(--teal); outline-offset: 1px; }
.rate-proposed-foot { display: flex; align-items: center; gap: 12px; margin-top: 8px; }

.rate-tick { width: 15px; height: 15px; accent-color: var(--teal); }

/* Unticked rows stay visible and go quiet — she is removing four of eight, and
   a row that vanishes on untick cannot be put back by looking at it. */
.rate-proposed tr.is-dropped td { opacity: .4; text-decoration: line-through; }

.cmp-note,
.cmp-said     { margin: 8px 0 0; font-size: .88rem; color: var(--ink-soft); }
.cmp-said     { font-style: italic; }
.cmp-opt-note { margin: 4px 0 0; font-size: .82rem; color: var(--ink-soft); }

/* auto-fit, not a fixed count: two quotes should fill the row and five should
   wrap, without a breakpoint per number. */
.cmp-options {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 12px;
  margin-top: 12px;
}

.cmp-option {
  display: flex;
  flex-direction: column;
  padding: 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.cmp-option.is-chosen {
  border-color: var(--pink);
  box-shadow: 0 0 0 1px var(--pink) inset;
}
/* The supplier's name leads the tile now, so it is no longer a caption under
   a picture — it is the first thing read. */
.cmp-option h5 { margin: 0; font-size: 1rem; }

/* .cmp-thumb was the 108px preview box that led each tile. Gone with the
   preview it framed — the tile now reads name, price, difference, then the
   document as a link. See the .cmp-price block further down. */

.cmp-option-foot {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: auto;
  padding-top: 10px;
}
.cmp-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }

/* ---------------------------------------------------------------------------
   The tile reads PRICE FIRST, and the document is a link underneath.

   An <object> preview of the PDF led this tile for one afternoon. It never
   rendered — see filePreviewHtml() in budgetfiles.js — and it was the wrong
   idea anyway: a couple reads this on a phone, and three tiles you have to
   open in turn is not a comparison. The two facts that answer the question at
   a glance are who and how much, so those carry the tile.
   --------------------------------------------------------------------------- */
.cmp-price {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
  font-size: 1.15rem;
  font-weight: 700;
  margin: 2px 0 0;
}
.cmp-price .is-none {
  font-size: .86rem; font-weight: 400; font-style: italic; color: var(--ink-faint);
}

/* How much more than the cheapest — the number they are actually weighing.
   Not red: this is a difference, not a problem. */
.cmp-delta {
  font-size: .74rem;
  font-weight: 500;
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  background: var(--surface-soft);
  color: var(--ink-soft);
  white-space: nowrap;
}
.cmp-delta.is-low { background: var(--ok-tint); color: var(--ok); }

/* The document, as a link rather than a picture. */
.cmp-doc {
  display: block;
  margin-top: 10px;
  font-size: .84rem;
  color: var(--pink-deep);
  text-decoration: underline;
  background: none;
  border: none;
  padding: 0;
  text-align: left;
  cursor: pointer;
}
.cmp-doc.is-empty { color: var(--ink-soft); font-style: italic; }
.cmp-doc.has-image {
  text-decoration: none;
  height: 120px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  border: 1px solid var(--line);
}
.cmp-doc img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* The category, beside the line's name — "Bloom & Co" tells you who, "Florist"
   tells you which decision this is. */
.cmp-cat {
  font-size: .72rem;
  color: var(--ink-soft);
  text-transform: uppercase;
  letter-spacing: .06em;
}

.cmp-price.is-none { color: var(--ink-faint); font-weight: 400; font-style: italic; }


/* ===========================================================================
   COMING UP — a colour block per couple. 11 September 2026.

   Gee, looking at the board this replaces: "I don't love the way this looks
   whatsoever, just design-wise." Then, choosing between ten drawn options:
   "I really love option 10" — and, before that, "I do want some colour. I do
   want it to stand out."

   WHAT CHANGED, and why each one is a fix rather than a preference:

   · The couple's hue was a 1.5px outline on a card in a two-column grid. It
     is now a BAND ACROSS THE PAGE. The hue's whole job is letting her know
     whose section she is in before she has read a word, and an outline at
     card size was the weakest possible way to say it.

   · Six of seven cards carried a red "N overdue" flag, so the couple with one
     late thing looked exactly like the couple with twenty-five. An alarm that
     is always on is not an alarm. Late is now a pill that only appears when
     something IS late, and the loudest thing on a band is the days-to-go
     number — which is the fact that actually decides what she does next.

   · Five stat tiles became a greeting, a sentence and at most three numbers.
     Two of the five tiles were permanently zero and as heavy as the real one.

   · The findings strip moved to the FOOT and turned orange. Orange is what a
     finding already wears here (§38.10); the red-pink it used to wear means
     somebody is waiting on you, which a finding is not.

   ⚠️ THE ROWS ARE THE SAME ROWS. .home-row, .home-tick, .home-when and
   .home-text are emitted by rowHtml() exactly as before, so ticking from the
   board, the deep link and the hover states are untouched. This block only
   re-places their columns and re-colours them. Do not fork the row.

   ⚠️ THE BLEED. .home-findings pulls -26px into .wrap's padding so the panel
   reaches the edge of the page rather than floating in the column. 26px is
   .wrap's padding in styles.css and 15px is its padding under 620px — if
   either changes, this has to change with it.

   ⚠️ .hb-bands USED TO BLEED TOO AND NO LONGER DOES. The bands became
   separated cards on 16 September, and a card with a rounded corner wants the
   column's gutter rather than to hang over it. Both the desktop rule and the
   620px override were changed together; changing one alone is how a corner
   ends up off the side of a phone.
   =========================================================================== */

/* ---- the masthead ------------------------------------------------------- */

.home-mast { margin: 0 0 18px; }

.hm-date {
  margin: 0 0 5px;
  font-size: .72rem;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--teal-deep);
}

.hm-hi {
  margin: 0 0 7px;
  font-family: var(--display);
  font-size: 2rem;
  font-weight: 800;
  letter-spacing: -.03em;
  line-height: 1.03;
  color: var(--ink);
}

/* The name is the only pink on the page above the fold. Not italic — <em> is
   the right element for "this word is the one that matters" and the slant is
   turned off deliberately. */
.hm-hi em { font-style: normal; color: var(--pink); }

.hm-say { margin: 0 0 5px; font-size: 1rem; color: var(--ink-soft); max-width: 58ch; }
.hm-say b { color: var(--ink); font-weight: 800; }

.hm-count { margin: 0; font-size: .8rem; color: var(--ink-faint); }

.hm-nums { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }

/* A zero is never drawn — home.js leaves it out entirely rather than styling
   it quietly, which is the same rule the tab counts follow. */
.hm-num {
  min-width: 84px;
  padding: 10px 14px;
  border-radius: var(--radius-sm);
  background: var(--surface-soft);
  text-align: center;
}

.hm-num b {
  display: block;
  font-family: var(--display);
  font-size: 1.5rem;
  font-weight: 800;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.hm-num span {
  display: block;
  margin-top: 4px;
  font-size: .64rem;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.hm-num.is-late { background: var(--late-tint); }
.hm-num.is-late b,
.hm-num.is-late span { color: var(--late); }

/* Grape, because it is already what "the couple's own edits" wears. A couple
   waiting on an answer is not late and must not borrow the red. */
.hm-num.is-ask { background: var(--c-indigo-tint); }
.hm-num.is-ask b,
.hm-num.is-ask span { color: var(--c-indigo); }


/* ---- the window pills --------------------------------------------------- */

/* Two pills used to sit here in solid brand pink answering two different
   questions, which read as one selection. There is one question now, and the
   label says which. */
.home-bar-lab {
  font-size: .68rem;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-faint);
}


/* ---- a band per couple -------------------------------------------------- */

/* One card per couple, with the colour down the side.

   Gee, 16 September, looking at three weddings on the board: "This is very
   hard to distinguish the weddings here." Measured, two of the three tints
   were six points of red apart - see hueOf() in home.js for that half of it.

   The other half is here. The bands used to sit flush against each other with
   a 3px rule on top, which reads as ONE striped sheet rather than as three
   things. So: a gap, a corner, a hairline, and the colour moved from the top
   edge to a 7px spine down the LEFT, where it runs the full height of the card
   instead of being a line above it. The block a wedding occupies is then
   obvious without reading a word.

   ⚠️ The negative margin is gone with the flush edges. It existed to bleed the
   bands to the panel's edge; a separated card wants the panel's own padding,
   and leaving it would hang the corners over the sides. */
.hb-bands {
  display: grid;
  gap: 11px;
}

.hb-band {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 176px;
  gap: 24px;
  padding: 16px 22px 14px;
  background: var(--hue-soft);
  border: 1px solid var(--line);
  border-left: 7px solid var(--hue);
  border-radius: 12px;
  box-shadow: 0 1px 2px rgb(0 0 0 / 5%);
}

/* One custom property per couple, set once, read by everything inside. The
   six cool hues are the app's own --cu-* set: 150°–300°, nothing warm, so
   overdue red stays the only warm thing on the page (§34). */
.hb-band.hue-0 { --hue: var(--cu-1); --hue-soft: var(--cu-1-soft); }
.hb-band.hue-1 { --hue: var(--cu-2); --hue-soft: var(--cu-2-soft); }
.hb-band.hue-2 { --hue: var(--cu-3); --hue-soft: var(--cu-3-soft); }
.hb-band.hue-3 { --hue: var(--cu-4); --hue-soft: var(--cu-4-soft); }
.hb-band.hue-4 { --hue: var(--cu-5); --hue-soft: var(--cu-5-soft); }
.hb-band.hue-5 { --hue: var(--cu-6); --hue-soft: var(--cu-6-soft); }

/* min-width:0, or a long task title pushes the 1fr column past the band and
   the days-to-go number slides off the right-hand edge. The grid's minmax(0)
   already covers it; this covers the column's own contents. */
.hb-main { min-width: 0; }

.hb-nm {
  margin: 0;
  font-family: var(--display);
  font-size: 1.5rem;
  font-weight: 800;
  letter-spacing: -.02em;
  line-height: 1.1;
  color: var(--hue);
}

.hb-dt { margin: 2px 0 0; font-size: .82rem; color: var(--ink-soft); }

.hb-rows { margin-top: 10px; }

/* The row's own columns, re-placed: tick, what, when. The date goes to the
   right-hand end because inside a band every row belongs to one couple, so
   the thing you scan down the left is what it IS, not when it is. */
.hb-band .home-row {
  grid-template-columns: 18px minmax(0, 1fr) auto;
  gap: 14px;
  padding: 8px;
  background: none;
  border-top: 1px solid rgba(42, 33, 38, .09);
  border-radius: var(--radius-sm);
}

/* ⚠️ grid-row: 1 ON ALL THREE, AND IT IS LOAD-BEARING.
   rowHtml emits them in the order tick, when, text — but they are placed here
   as tick, text, when, because the date belongs at the right-hand end. Naming
   only the COLUMN puts the date in column 3 of row 1, moves the cursor past
   column 2, and then sparse auto-placement drops the text into ROW 2. Live,
   that read as the date floating on a line of its own above every task and a
   92px row where 40px was intended. Pinning the row is the whole fix. */
.hb-band .home-row .home-tick { grid-column: 1; grid-row: 1; }
/* ⚠️ 600, NOT 700, AND THE REASON IS THE TWO THINGS EITHER SIDE OF IT.

   Gee, 16 September: "can you make them bold so they stand out a bit more,
   because at the moment it's a bit hard to read". They were 400 - regular body
   weight - on a tinted card, which is the lightest thing on the whole board.

   But the couple's name above is 800 and the overdue chip to the right is 700.
   Take the task to 700 and it ties with the date it sits beside, so the row
   stops having a first thing to read. 600 is clearly heavier than what she was
   looking at and still sits below both of its neighbours.

   ⚠️ AND THE SUB-LINE HAS TO BE PUT BACK EXPLICITLY. font-weight inherits,
   and .home-text small only sets size, colour and spacing - so bolding the
   task silently bolded the supplier line under it too, and the row went flat
   at 600 throughout. Caught by reading the computed weight off the live page
   after deploying, not by reading this file. */
.hb-band .home-row .home-text { grid-column: 2; grid-row: 1; font-weight: 600; }
.hb-band .home-row .home-text small { font-weight: 400; }
.hb-band .home-row .home-when { grid-column: 3; grid-row: 1; text-align: right; }

/* A white wash, so one hover works on all six pastels and cannot go warm. */
.hb-band .home-row:hover { background: var(--cu-hover); }

/* Visible without hovering — ticking from the board is the reason it is there
   — and in the couple's own hue, so no seventh colour enters. */
.hb-band .home-row .home-tick { opacity: .7; accent-color: var(--hue); }
.hb-band .home-row:hover .home-tick,
.hb-band .home-row .home-tick:checked,
.hb-band .home-row .home-tick:focus-visible { opacity: 1; }

.hb-more {
  margin-top: 8px;
  padding: 5px 8px;
  font: inherit;
  font-size: .8rem;
  font-weight: 800;
  color: var(--hue);
  background: none;
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.hb-more:hover { background: var(--cu-hover); }


/* ---- the right-hand side of a band -------------------------------------- */

.hb-side { text-align: right; }

.hb-big {
  display: block;
  font-family: var(--display);
  font-size: 2.6rem;
  font-weight: 800;
  line-height: 1;
  color: var(--hue);
  font-variant-numeric: tabular-nums;
}

.hb-lab {
  display: block;
  margin-top: 4px;
  font-size: .64rem;
  font-weight: 800;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* "No date yet" and "Today" have no number in front of them, so they carry the
   weight themselves rather than sitting there as a caption for nothing. */
.hb-lab.is-alone {
  font-family: var(--display);
  font-size: 1.15rem;
  letter-spacing: -.01em;
  text-transform: none;
  color: var(--ink-soft);
}

.hb-lab.is-today { color: var(--pink-deep); }

.hb-facts {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 5px;
  margin-top: 12px;
}

.hb-fact {
  padding: 3px 10px;
  border-radius: var(--radius-pill);
  font-size: .72rem;
  font-weight: 800;
  white-space: nowrap;
  background: rgba(255, 255, 255, .8);
  color: var(--ink-soft);
}

/* Three meanings, three colours that already mean them everywhere else. */
.hb-fact.is-late { background: var(--late-tint);     color: var(--late); }
.hb-fact.is-ask  { background: var(--c-indigo-tint); color: var(--c-indigo); }
.hb-fact.is-paid { background: var(--ok-tint);       color: var(--ok); }


/* ---- the findings strip, at the foot ------------------------------------ */

#home-problems-row { margin-top: 24px; }

.home-findings {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  width: auto;
  margin: 0 -26px;
  padding: 15px 26px;
  background: var(--warn-tint);
  border: 0;
  border-top: 3px solid var(--btn-tangerine);
  font: inherit;
  text-align: left;
  color: var(--ink);
  cursor: pointer;
}

.home-findings:hover { background: #ffe4c4; }

.hfd-n {
  font-family: var(--display);
  font-size: 1.7rem;
  font-weight: 800;
  line-height: 1;
  color: var(--warn);
  font-variant-numeric: tabular-nums;
}

.hfd-say { font-size: .92rem; font-weight: 600; }

.hfd-say small {
  display: block;
  margin-top: 2px;
  font-size: .78rem;
  font-weight: 400;
  color: var(--ink-soft);
}

.hfd-go {
  margin-left: auto;
  font-size: .8rem;
  font-weight: 800;
  color: var(--warn);
  white-space: nowrap;
}


/* ---- narrower ----------------------------------------------------------- */

@media (max-width: 820px) {
  /* The countdown stops being a column and becomes a line above the rows —
     stacking a 2.6rem number over a 176px column on a phone wastes the half
     of the band that carries the actual work. */
  .hb-band { grid-template-columns: minmax(0, 1fr); gap: 10px; }
  .hb-side { display: flex; align-items: baseline; flex-wrap: wrap; gap: 12px; text-align: left; }
  .hb-big  { font-size: 1.9rem; }
  .hb-lab  { margin-top: 0; }
  .hb-facts { flex-direction: row; align-items: center; margin-top: 0; }
}

@media (max-width: 620px) {
  /* .wrap drops to 15px of side padding here, so the bleed has to match it or
     the panel hangs off the edge of the screen.

     ⚠️ .hb-bands IS NO LONGER IN THIS LIST. The bands became separated cards
     with rounded corners on 16 September; bleeding them past the padding would
     hang those corners off both sides of a phone. A card wants the gutter that
     a flush stripe did not. */
  .home-findings { margin-left: -15px; margin-right: -15px; }
  .hb-band,
  .home-findings { padding-left: 15px; padding-right: 15px; }
  .hm-hi { font-size: 1.6rem; }
  .hb-nm { font-size: 1.3rem; }
}


/* ---------------------------------------------------------------------------
   THE COUPLE'S PAPERWORK, on their supplier card. 13 September, migration 107.

   Gee: "that needs to be visible to me and the couple when we're looking at
   their wedding and we're looking at that supplier tab. It is crucial."

   The list itself is the SAME .sf-* markup Gee's card draws (checks.css), with
   the write controls left out — this block is only the frame it sits in. Two
   copies of one list is how the couple's phase headings drifted from the
   planner's; see the warning at the top of .portal-phase above.
   --------------------------------------------------------------------------- */
.portal-supplier-docs {
  margin-top: 10px;
  padding-top: 9px;
  border-top: 1px solid var(--line);
}

.portal-supplier-docs-head {
  font-size: .72rem;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 4px;
}

/* ---------------------------------------------------------------------------
   The paperwork, folded once there are two or more.

   Gee, 20 September: "The documents should be collapsed because that's just
   going to get way too messy with all of that information in there." Navid
   Forogh alone drew five rows on Pardesay's page.

   ⚠️ THE CARET IS DRAWN HERE, exactly as .set-fold does it a few hundred lines
   above. A <summary> with list-style:none and no arrow of its own is a heading
   nobody knows they can press — `a-control-you-have-to-be-told-about`.

   ⚠️ AND THE HEAD KEEPS ITS OWN TYPOGRAPHY. This selector only adds the row
   layout and the pointer; the uppercase label above still decides how it
   looks, so the folded card and the open one read as the same thing.
   --------------------------------------------------------------------------- */
.portal-docs-fold > summary {
  display: flex;
  align-items: center;
  gap: .4rem;
  cursor: pointer;
  list-style: none;
  border-radius: 6px;
  padding: .1rem .3rem;
  margin-inline: -.3rem;
}
.portal-docs-fold > summary::-webkit-details-marker { display: none; }

.portal-docs-fold > summary::before {
  content: "▾";
  font-size: .9em;
  color: var(--ink-faint, #a0949a);
  transition: transform .12s ease;
}
.portal-docs-fold:not([open]) > summary::before { transform: rotate(-90deg); }

.portal-docs-fold > summary:hover { background: var(--ground-soft, rgba(0,0,0,.035)); }
.portal-docs-fold > summary:focus-visible {
  outline: 2px solid var(--calm, #007c85);
  outline-offset: 2px;
}

/* The count. Deliberately not uppercase-bold like the label beside it — it is
   the quiet half of the sentence, and two shouting words would read as two
   headings. */
.portal-docs-n {
  font-weight: 500;
  letter-spacing: normal;
  text-transform: none;
  font-size: .78rem;
  color: var(--ink-faint);
}

/* ---------------------------------------------------------------------------
   A file row inside a supplier CARD, which is a third the width of the table
   it was designed for.

   🛑 MEASURED, NOT GUESSED. Gee sent a screenshot on 20 September where Nima
   Creates' one agreement read as a vertical ribbon of words. The card is 282px
   wide; `.sf-row` is `auto minmax(0,1fr) auto`, and with an 85px chip, a 60px
   Open button and two 11px gaps, the FILE NAME was left 76px — and 84px tall.

   ⚠️ IT IS THE SHARED LIST DOING ITS JOB, NOT A BUG IN IT. That grid is right
   on Gee's supplier screen, where the row has the width of a table. The fix
   belongs here, scoped to the card, rather than in checks.css where it would
   change her screen too — `make-it-look-like-that-means-reuse-those-classes`
   cuts both ways: reuse the markup, adjust it where the container differs.

   Chip and Open share the top line; the name gets the full width beneath.
   Explicit areas rather than auto-placement, because auto-placement with a
   spanning child pushes the third item onto a row of its own.

   ⚠️ APPLIES TO FOLDED AND UNFOLDED ALIKE — checked in the couple's preview:
   both draw the same .sf-kind / .sf-meta / .sf-actions children.
   --------------------------------------------------------------------------- */
.portal-supplier .sf-row {
  grid-template-columns: auto 1fr;
  grid-template-areas:
    "kind actions"
    "name name";
  row-gap: 5px;
  column-gap: 8px;
}
.portal-supplier .sf-kind    { grid-area: kind; justify-self: start; }
.portal-supplier .sf-actions { grid-area: actions; justify-self: end; }
.portal-supplier .sf-meta    { grid-area: name; }

/* The couple's own "Add a document" — migration 131.

   ⚠️ IT IS DELIBERATELY QUIET. This sits under a supplier's paperwork on a
   page whose job is reassurance, not data entry; a solid primary button there
   would read as the main thing to do on the card. Ghost until hovered. */
.portal-docs-add { margin-top: 8px; }

.portal-docs-empty { border-top: 1px solid var(--line); padding-top: 9px; }

.portal-docs-addbtn {
  font: inherit;
  font-size: .78rem;
  font-weight: 600;
  color: var(--ink-faint);
  background: none;
  border: 1px dashed var(--line);
  border-radius: 7px;
  padding: .3rem .6rem;
  cursor: pointer;
  transition: color .12s ease, border-color .12s ease;
}
.portal-docs-addbtn:hover:not(:disabled) {
  color: var(--calm, #007c85);
  border-color: var(--calm, #007c85);
  border-style: solid;
}
.portal-docs-addbtn:focus-visible {
  outline: 2px solid var(--calm, #007c85);
  outline-offset: 2px;
}
.portal-docs-addbtn:disabled { opacity: .6; cursor: default; }

/* Nothing they can press belongs on a printed page. */
@media print { .portal-docs-add { display: none; } }

/* 🛑 PRINTING IS HANDLED IN JS, NOT HERE, AND THAT IS DELIBERATE.
   A closed <details> cannot be forced open with CSS — the browser hides its
   contents itself, and `display` on the children does not override it. The
   first version of this block tried exactly that and would have shipped a
   supplier list printing as five empty headings. portal.js opens every fold on
   `beforeprint` and puts them back on `afterprint`. All this does is drop the
   caret, which means nothing on paper. */
@media print {
  .portal-docs-fold > summary::before { display: none; }
  .portal-docs-fold > summary { cursor: auto; }
}

/* On a phone the row has no write buttons to make room for, so the name gets
   the width instead of a third column that is always empty. */
#portal-view .sf-row { grid-template-columns: auto minmax(0, 1fr) auto; }
#portal-view .sf-actions { justify-content: flex-end; }

/* The shortcut from the contact card onto the day. Gee, 15 September, straight
   after her first Keep: "where is the button for the shortcuts in here as
   well?" Keeping the hour and putting it on the run sheet are one thought. */
.needs-toRun {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
}

/* ---------------------------------------------------------------------------
   "This is a …" — the chooser on a document in a budget line's paperwork list.
   Added 20 September: the kind used to be a word buried in the grey sub-line
   and there was no way to change it.

   Quiet until you go near it. It is a correction, not the point of the row —
   the file's name is.
   --------------------------------------------------------------------------- */
.fkind {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
}

.fkind > .k {
  color: var(--ink-faint);
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .03em;
  text-transform: uppercase;
}

/* ⚠️ width: auto, NOT the bare `select { width: 100% }` in styles.css — that
   rule is element-based, so a class alone does not beat it for width. */
.fkind > select {
  width: auto;
  min-width: 0;
  padding: 2px 6px;
  border: 1px solid var(--line);
  border-radius: 5px;
  background: var(--surface);
  color: var(--ink);
  font-family: inherit;
  font-size: .78rem;
  font-weight: 600;
}

.fkind > select:focus-visible {
  outline: 2px solid var(--calm, #007c85);
  outline-offset: 1px;
}

/* ---------------------------------------------------------------------------
   "Move to" — sending a file to another home from its own row.
   Added 20 September, beside Rename. Same quiet treatment as the "This is a"
   chooser: a correction, not the point of the row.
   --------------------------------------------------------------------------- */
.fmove {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.fmove > .k {
  color: var(--ink-faint);
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .03em;
  text-transform: uppercase;
}

/* ⚠️ width: auto and a max, NOT the bare `select { width: 100% }` in
   styles.css — a task's label can be ninety characters and would otherwise
   stretch the row off the screen. */
.fmove > select {
  width: auto;
  max-width: 190px;
  min-width: 0;
  padding: 2px 6px;
  border: 1px solid var(--line);
  border-radius: 5px;
  background: var(--surface);
  color: var(--ink);
  font-family: inherit;
  font-size: .78rem;
  font-weight: 600;
}

.fmove > select:disabled { opacity: .55; }

.fmove > select:focus-visible {
  outline: 2px solid var(--calm, #007c85);
  outline-offset: 1px;
}


/* ==========================================================================
   THE CHECKLIST ROW — 21 September 2026
   ==========================================================================
   Gee: *"This screen just looks so messy and so confusing… it's just very hard
   to understand."* Measured on her live checklist before anything was drawn:

     the task name              14.4px
     the ★                      16.3px     ← bigger than the name
     the + and the ⋮            15.5px     ← bigger than the name
     15 different text sizes on one screen, all between 9.9 and 16.3
     13 different text colours
     357px of buttons and chips to the LEFT of the name, on a 1,168px row

   The name of the job was the sixth of seven things in the row and smaller
   than three of them, so the eye had nowhere to land. Same fault as the
   printed run sheet on 18 September, where the title was 13.0px and the note
   under it 12.7px — `measure-the-card-before-redrawing-it`.

   She was shown three options and picked this one: raise the name, quieten the
   furniture, and change NOTHING about the layout. Nothing moves, nothing is
   hidden, no markup changed. `add-it-do-not-rebuild-it`.

   🛑 SCOPED TO #task-groups, WHICH IS HER CHECKLIST AND ONLY HERS.
   The couple draw their tasks from the same `rowHtml` inside #portal-body and
   she never looks at that screen, so a change leaking into it is heard from
   the couple or not at all — `scope-to-the-screen-not-the-section`.

   ⚠️ THE TITLE HAD TO BE SET HERE, NOT IN styles.css. `.task-title` is
   declared in both files at equal specificity and bloom loads later; the
   comment at line 469 of this file already says so, and it is why the id
   scope below sits at (1,1,0) rather than fighting it.
   -------------------------------------------------------------------------- */

/* The name leads. 1.1rem = 17px at this root, against the 16.3px star. */
#task-groups .task-title { font-size: 1.1rem; }

/* The star stops competing. .9rem = 14px, and --pink-deep is measurably
   EASIER to read than the electric --pink it replaces: 5.82:1 on white
   against 4.33:1. Quieter and more legible are not opposites here. */
#task-groups .task-star { font-size: .9rem; }
#task-groups .task-star.is-on { color: var(--pink-deep); }
/* ⚠️ Hover feedback would otherwise be lost: the rule above is (1,2,0) and
   `.task-star:hover` is (0,2,0), so the on-state would stop reacting. */
#task-groups .task-star.is-on:hover { color: var(--pink); }

/* The ⋮ and the + were 15.5px — the same size as the name. They keep their
   boxes, their hovers and their hit targets; only the glyph shrinks. */
#task-groups .row-gutter .row-dots { font-size: .84rem; }

/* Gee and Pardesay were teal 600 inside a teal pill, competing with the name
   from 11.2px. Still there, still in the same 84px column, no longer shouting.
   ⚠️ `:not(.is-empty)` — an empty slot has its own quieter treatment already
   and must keep it. */
#task-groups .who-name:not(.is-empty) {
  border-color: transparent;
  color: var(--ink-soft);
  font-weight: 500;
}

/* The date was the same near-black as the name, so both ends of the row read
   as equally important.
   🛑 THE TWO EXCLUSIONS ARE LOAD-BEARING, NOT TIDINESS. Without them this
   (1,1,0) rule beats `.task-due.is-overdue` (0,2,0) and greys out a LATE date,
   and beats `.task-due.is-empty` (0,2,0) and paints a placeholder onto every
   dateless row. "Make it consistent" is how meaning gets deleted —
   `accent-color-only-paints-a-ticked-box`. */
#task-groups .task-due:not(.is-overdue):not(.is-empty) { color: var(--ink-faint); }

/* ============================================================================
   Coming up · To do and Payments side by side (1 Oct 2026)
   Gee: "The payments and the to-do list are too combined now. I can't
   actually tell the difference." She chose B + C, square colour 2: payments in
   a pale mint panel, each amount in a pink square. The band itself now takes
   the couple's stored colour through --hue / --hue-soft set inline by home.js
   from couplecolour.js (the old .hue-N classes are no longer emitted).
   ============================================================================ */
.hb-cols {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 12px;
  margin-top: 10px;
}
.hb-cols.is-one { grid-template-columns: minmax(0, 1fr); }
.hb-cols .hb-rows { margin-top: 4px; }

.hb-todo,
.hb-pay {
  min-width: 0;
  border-radius: 10px;
  padding: 10px 12px;
}
.hb-todo { background: #fff; }
.hb-pay  { background: #e6f7ef; border: 2px solid #16a36a; }

.hb-col-h {
  margin: 0 0 4px;
  font-size: .72rem;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
}
.hb-todo .hb-col-h { color: var(--hue); }
.hb-pay  .hb-col-h { color: #0e7a4f; }

/* Four parts on a payment row: tick, amount square, who/what, when. Every one
   pinned to row 1 — the same trap the note on .hb-band .home-row describes. */
.hb-band .hb-pay-row { grid-template-columns: 18px auto minmax(0, 1fr) auto; gap: 10px; align-items: center; }
.hb-band .hb-pay-row .home-tick { grid-column: 1; grid-row: 1; }
.hb-band .hb-pay-row .hb-amt    { grid-column: 2; grid-row: 1; }
.hb-band .hb-pay-row .home-text { grid-column: 3; grid-row: 1; }
.hb-band .hb-pay-row .home-when { grid-column: 4; grid-row: 1; text-align: right; }
.hb-band .hb-pay-row { border-top-color: rgba(14, 122, 79, .15); }

.hb-amt {
  background: var(--pink);
  color: #fff;
  font-weight: 800;
  font-size: .82rem;
  border-radius: 8px;
  padding: 3px 8px;
  min-width: 66px;
  text-align: center;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.hb-held {
  display: inline-block;
  margin-left: 4px;
  padding: 0 6px;
  border: 1px solid #e8c56f;
  border-radius: 999px;
  background: #fff;
  color: #8a5a00;
  font-size: .7rem;
  font-weight: 700;
}

@media (max-width: 760px) {
  .hb-cols { grid-template-columns: minmax(0, 1fr); }
}

/* ============================================================================
   The Weddings page · each card in its couple's colour (1 Oct 2026)
   Gee: "everything looks the same… I can't identify the couples." --hue and
   --hue-soft are set inline from couplecolour.js, the same colour Coming up and
   the preview email use. The name becomes a solid header strip, as in the
   mock-up she approved. Celebrancy cards are untouched (their own mint, 29 Aug).
   ============================================================================ */
.wedding-card.is-coloured {
  border-color: var(--hue);
  background: linear-gradient(180deg, var(--hue-soft) 0%, var(--surface) 70%);
  overflow: hidden;
}
.wedding-card.is-coloured:hover { border-color: var(--hue); }
.wedding-card.is-coloured .card-name {
  margin: -20px -22px 12px;
  padding: 12px 22px;
  background: var(--hue);
  color: #fff;
}
.wedding-card.is-coloured .progress-bar span { background: var(--hue); }
