/* CS Shootboard
   ------------------------------------------------------------------
   Two surfaces: phone = call-sheet cards · desktop = spreadsheet sheet + month grid.
   day (default) = paper in daylight on a shoot day · night = studio black.

   TYPE — one face (Inter), hierarchy from weight and scale only. Six steps,
   no drift: 10 label · 13 data · 15 body · 20 title · 28 section · display.
   Weight contrast does the work: 800 for the one loud thing, 500 for the rest.

   MATERIAL — panels are frosted glass: translucent fill, backdrop blur, a 1px
   border and an inset top highlight for the lit edge. This is a web
   approximation of the Apple frosted-glass idiom, not an Apple material. Blur
   only reads against a non-flat backdrop, so `.ambient` lays two very soft
   tint fields behind everything for the glass to sample. Solid fallback under
   prefers-reduced-transparency.

   COLOR — teal is the one action accent; brass = needs a human;
   red = tally (unverified). Both themes designed together, not inverted.

   SHAPE — containers 16px · fields 10px · controls full pill. No other radii. */

* { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  color-scheme: light;

  --bg: #e9e6de;
  --ink: #16150f;
  --ink-2: rgba(22, 21, 15, .64);
  --ink-3: rgba(22, 21, 15, .38); /* decoration only — under AA, never for text that informs */
  --muted: #6b6558;
  --line: rgba(22, 21, 15, .10);
  --line-2: rgba(22, 21, 15, .18);

  --teal: #04716d;
  --teal-hi: #025c59;
  --teal-tint: rgba(4, 113, 109, .11);
  --teal-line: rgba(4, 113, 109, .34);
  --brass: #7c5c24;
  --brass-tint: rgba(124, 92, 36, .09);
  --brass-line: rgba(124, 92, 36, .34);
  --rec: #b32a30;
  --rec-tint: rgba(179, 42, 48, .10);
  --rec-line: rgba(179, 42, 48, .34);

  /* glass, day: white-ish panes lifting off a warm tinted field */
  --glass: linear-gradient(158deg, rgba(255, 255, 255, .80), rgba(255, 255, 255, .52));
  --glass-2: linear-gradient(158deg, rgba(255, 255, 255, .94), rgba(255, 255, 255, .70));
  --glass-bd: rgba(22, 21, 15, .10);
  --glass-in: inset 0 1px 0 rgba(255, 255, 255, .92);
  --glass-sh: 0 6px 20px rgba(22, 21, 15, .06);
  --glass-sh-2: 0 12px 34px rgba(22, 21, 15, .10);
  --fill: rgba(22, 21, 15, .055); /* neutral fill — teal stays a signal, never decoration */
  --blur: blur(20px) saturate(155%);
  --blur-lite: blur(13px) saturate(140%);
  --bar-bg: rgba(233, 230, 222, .62);
  /* A menu is the one surface here that is NOT glass. It floats over cards, so
     whatever is under it must not read through it — a shoot's own time showing
     faintly behind "client team" is the kind of thing you only see once you
     look. Solid, one step lighter than the ground it sits on. */
  --menu-bg: #fbfaf7;

  /* ambient tint fields the blur samples */
  --amb-1: rgba(4, 113, 109, .085);
  --amb-2: rgba(163, 122, 52, .085);
  --grain-op: .045;
  --grain-blend: multiply;

  /* client identity. The hue itself (--ch) is set per element in app.js, now
     from the whole wheel (his call); these only say how bright and how
     saturated any hue is allowed to be in this theme, which is what keeps a
     rainbow of clients looking like one palette. Any element without a --ch
     falls back to transparent/inherited, which is the wanted result. */
  --cl-s: 62%;
  --cl-l: 36%;
  --cl-tint-s: 64%;
  --cl-tint-l: 91%;

  --sans: 'Inter', -apple-system, 'Segoe UI', sans-serif;
  --ease: cubic-bezier(.16, 1, .3, 1);
  --r-card: 16px;
  --r-field: 10px;
  --r-pill: 999px;
}

/* night: the same instrument in the dark — re-mixed, not inverted */
html[data-theme="night"] {
  color-scheme: dark;

  --bg: #0c0c0e;
  --ink: #eeeae3;
  --ink-2: rgba(238, 234, 227, .62);
  --ink-3: rgba(238, 234, 227, .34);
  --muted: #9a948a;
  --line: rgba(255, 255, 255, .085);
  --line-2: rgba(255, 255, 255, .16);

  --teal: #10b3ab;
  --teal-hi: #35ccbd;
  --teal-tint: rgba(16, 179, 171, .14);
  --teal-line: rgba(16, 179, 171, .34);
  --brass: #d0a765;
  --brass-tint: rgba(208, 167, 101, .10);
  --brass-line: rgba(208, 167, 101, .32);
  --rec: #f0575c;
  --rec-tint: rgba(240, 87, 92, .14);
  --rec-line: rgba(240, 87, 92, .34);

  --glass: linear-gradient(158deg, rgba(255, 255, 255, .062), rgba(255, 255, 255, .022));
  --glass-2: linear-gradient(158deg, rgba(255, 255, 255, .10), rgba(255, 255, 255, .04));
  --glass-bd: rgba(255, 255, 255, .10);
  --glass-in: inset 0 1px 0 rgba(255, 255, 255, .10);
  --glass-sh: 0 8px 26px rgba(0, 0, 0, .34);
  --glass-sh-2: 0 14px 40px rgba(0, 0, 0, .46);
  --fill: rgba(255, 255, 255, .07);
  --bar-bg: rgba(12, 12, 14, .60);
  --menu-bg: #1e1e22;

  --amb-1: rgba(16, 179, 171, .13);
  --amb-2: rgba(208, 167, 101, .075);
  --grain-op: .038;
  --grain-blend: normal;

  --cl-s: 64%;
  --cl-l: 70%;
  --cl-tint-s: 44%;
  --cl-tint-l: 21%;
}

html { -webkit-text-size-adjust: 100%; }

body {
  background: var(--bg);
  color: var(--ink);
  font: 500 15px/1.5 var(--sans);
  font-variant-numeric: tabular-nums;
  min-height: 100dvh;
  padding-bottom: calc(56px + env(safe-area-inset-bottom));
  transition: background .3s var(--ease), color .3s var(--ease);
}

/* the field the glass samples — without it, blur has nothing to do */
.ambient {
  position: fixed; inset: 0; z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(58vw 52vh at 8% -6%, var(--amb-1), transparent 72%),
    radial-gradient(62vw 58vh at 104% 34%, var(--amb-2), transparent 70%),
    radial-gradient(70vw 50vh at 46% 108%, var(--amb-1), transparent 74%);
  transition: background .3s var(--ease);
}

/* film grain over everything — matte, not vector void */
body::after {
  content: '';
  position: fixed; inset: 0; z-index: 60;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 160px 160px;
  opacity: var(--grain-op);
  mix-blend-mode: var(--grain-blend);
}

::selection { background: var(--teal-line); }

/* ---- the glass recipe ---- */
.card, .sheet-wrap, button.mnav, #notice {
  background-color: transparent; /* <button> defaults to opaque buttonface — reset before the glass fill */
  background-image: var(--glass);
  border: 1px solid var(--glass-bd);
  box-shadow: var(--glass-in), var(--glass-sh);
  -webkit-backdrop-filter: var(--blur-lite);
  backdrop-filter: var(--blur-lite);
}
.sheet-wrap, #notice {
  -webkit-backdrop-filter: var(--blur);
  backdrop-filter: var(--blur);
}
@media (prefers-reduced-transparency: reduce) {
  .card, .sheet-wrap, button.mnav, #notice, nav#tabs {
    background-image: none;
    background-color: var(--bg);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}

/* ---- silkscreen: the small printed label ---- */
.eyebrow, .day-head .d, .today-tag, .field .k, .swatches .k, .status, .runby, .conf,
.sect .t, .sect .n, .source summary, .sub, .diff .dk, .empty-state .e,
.dow, .hero .k {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* ---- masthead ---- */
header {
  max-width: 1200px;
  margin: 0 auto;
  padding: calc(20px + env(safe-area-inset-top)) 18px 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
h1 {
  font-size: 21px;
  font-weight: 800;
  letter-spacing: -.03em;
  line-height: 1;
}
.meta { margin-top: 8px; }

.mast-tools { display: flex; align-items: center; gap: 0; margin-right: -6px; }

/* Theme, import and export are maintenance, not content. They keep a real
   40px hit area and an accessible name, but no pane, border or shadow — the
   glass here was making three switches shout as loudly as the schedule. */
.icon-btn {
  appearance: none;
  background: none;
  border: 0;
  box-shadow: none;
  font: inherit;
  cursor: pointer;
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  border-radius: var(--r-pill);
  color: var(--ink-3);
  text-decoration: none;
  transition: color .2s var(--ease), transform .15s var(--ease);
}
.icon-btn:hover { color: var(--ink-2); }
.icon-btn:active { transform: scale(.94); }
.icon-btn[disabled], .icon-btn[aria-disabled="true"] { opacity: .45; pointer-events: none; }

.tool-pair { display: flex; align-items: center; }

/* Share is not a third file control. It sits with import/export but a
   hairline sets it off, and it wears the action teal — the same "this does
   something outward" colour the rest of the board uses — so at a glance the
   grey pair moves files and the teal one sends the schedule to people. */
.share-btn {
  color: var(--teal);
  position: relative;
  margin-left: 5px;
}
.share-btn::before {
  content: "";
  position: absolute;
  left: -3px;
  top: 50%;
  transform: translateY(-50%);
  width: 1px;
  height: 18px;
  background: var(--line-2);
}
.share-btn:hover { color: var(--teal-hi); }

.i { width: 16px; height: 16px; display: block; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
html[data-theme="day"] .i-sun { display: none; }
html[data-theme="night"] .i-moon { display: none; }

/* ---- tabs ---- */
nav#tabs {
  position: sticky; top: 0; z-index: 30;
  display: flex;
  justify-content: space-between;
  height: 48px;
  /* Line the tabs up with the column headers inside the box, not the box edge:
     main is max-width 1200 with 16px padding (inner edge at 50% - 584px) and
     .sheet th adds 14px, so "aaj" starts exactly where the D of DATE does. */
  padding: 0 max(30px, calc(50% - 570px));
  background: var(--bar-bg);
  -webkit-backdrop-filter: var(--blur);
  backdrop-filter: var(--blur);
  border-bottom: 1px solid var(--line);
}
nav#tabs button {
  appearance: none; background: none; border: 0; cursor: pointer;
  flex: 0 0 auto;
  min-width: 0;
  display: flex; align-items: center; justify-content: center; gap: 7px;
  padding: 0 2px;
  font: 700 11px/1 var(--sans);
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--muted);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color .2s var(--ease), border-color .2s var(--ease);
}
nav#tabs button.active { color: var(--teal-hi); border-bottom-color: var(--teal); }
.badge {
  font: 700 10px/1 var(--sans);
  font-variant-numeric: tabular-nums;
  color: var(--rec);
  background: var(--rec-tint);
  border: 1px solid var(--rec-line);
  border-radius: var(--r-pill);
  padding: 3px 7px;
  min-width: 21px;
  text-align: center;
}

/* The sliding underline. One element for the whole bar rather than a border on
   each button, so moving between tabs is a travel and not a jump-cut — the one
   detail that separates an app tab bar from six links in a row. Desktop keeps
   the per-button border; this rides above it and is only shown on a phone. */
.tabink {
  position: absolute;
  bottom: 0;
  left: 0;
  height: 2.5px;
  border-radius: 2px 2px 0 0;
  background: var(--teal);
  transform: translateX(var(--x, 0)) scaleX(var(--sx, 0));
  transform-origin: left center;
  width: 1px;
  display: none;
}
.tabink.placed { transition: transform .34s var(--ease); }
/* It travels; it does not fly in. Reduced-motion gets the position, not the ride. */
@media (prefers-reduced-motion: reduce) { .tabink.placed { transition: none; } }

/* ---- tabs, on a phone --------------------------------------------------
   Six tabs at 402px were being squeezed by their own letter-spacing: .13em on
   six uppercase words eats about 40px of a 402px screen, which is where the
   gaps went. Tracking comes down to .045em so the words can breathe.

   The spacing is deliberately NOT equal-width segments. Measured at 402px,
   equal sixths put 38.6px of air between "aaj" and "kal" and 14.8px between
   "mahina" and "verify" — the labels run from 27px to 54px, so equal boxes
   make unequal gaps. Content-width buttons with uniform padding and
   space-between put the SAME gap between every pair, which is the rhythm the
   eye actually reads. The 10px padding is what keeps every target over 44px
   wide even for a three-letter tab, and 4px of nav padding lands "aaj" on the
   same 14px left edge as the masthead above it. */
@media (max-width: 560px) {
  nav#tabs {
    position: sticky;
    height: 52px;
    padding: 0 4px;
    justify-content: space-between;
  }
  nav#tabs button {
    position: relative;
    flex: 0 0 auto;
    height: 100%;
    padding: 0 10px;
    gap: 0;
    font-size: 12px;
    letter-spacing: .045em;
    /* the travelling underline replaces the per-button border down here */
    border-bottom-color: transparent !important;
    -webkit-tap-highlight-color: transparent;
  }
  nav#tabs button.active { color: var(--teal-hi); }
  /* Pressed feedback that does not move the row: the label dims, nothing shifts. */
  nav#tabs button:active { opacity: .55; transition: opacity .06s linear; }
  .tabink { display: block; }
  /* A count is a mark on the tab, not another word in the row — inline it would
     make "verify" a third wider than every other segment. */
  .badge {
    position: absolute;
    top: 7px;
    left: 50%;
    margin-left: 14px;
    padding: 2px 4px;
    min-width: 15px;
    font-size: 9px;
    line-height: 1;
  }
}

/* ---- main ---- */
main {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px 16px 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.col { width: 100%; max-width: 680px; margin: 0 auto; display: flex; flex-direction: column; gap: 9px; }
/* On a phone the side padding is width the month grid needs for names. */
@media (max-width: 560px) {
  main { padding: 16px 12px 0; }
  header { padding: calc(16px + env(safe-area-inset-top)) 14px 12px; }
}

/* ---- today hero: the one loud thing ---- */
.hero { position: relative; padding: 12px 4px 12px 15px; }
/* It is also the way in to that shoot. The eyebrow carries the only mark it
   needs — a headline this big does not need a button drawn around it. */
.hero[data-hero] { cursor: pointer; border-radius: var(--r-card); }
.hero[data-hero] .k::after {
  content: '\2192';
  display: inline-block;
  margin-left: 7px;
  vertical-align: -1px;
  color: var(--ink-3);
  transition: transform .2s var(--ease), color .2s var(--ease);
}
.hero[data-hero]:active .k::after { transform: translateX(3px); }
@media (hover: hover) {
  .hero[data-hero]:hover .k::after { transform: translateX(3px); color: var(--ink-2); }
}
/* same mark as the cards: the client name wears the colour */
.hero[style*="--ch"] .hc {
  background: hsl(var(--ch) var(--cl-tint-s) var(--cl-tint-l));
  color: hsl(var(--ch) var(--cl-s) var(--cl-l));
  border-radius: 8px;
  padding: 3px 10px;
  margin-left: -10px;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
.hero .k { display: block; margin-bottom: 14px; }
.hero-line { display: flex; align-items: baseline; gap: 16px; flex-wrap: wrap; }
.hero .ht {
  font-size: clamp(52px, 14vw, 76px);
  font-weight: 800;
  line-height: .86;
  letter-spacing: -.045em;
  font-variant-numeric: tabular-nums;
}
.hero .hc {
  font-size: clamp(19px, 4.4vw, 25px);
  font-weight: 600;
  letter-spacing: -.02em;
  color: var(--ink-2);
}
.hero-sub { margin-top: 12px; font-size: 13px; font-weight: 500; color: var(--muted); }

/* ---- day groups (card views) ---- */
.day { display: flex; flex-direction: column; gap: 12px; }
.day + .day { margin-top: 16px; }
.day-head { display: flex; align-items: center; gap: 12px; padding: 0 4px; }
.day-head .d { color: var(--ink-2); }
.today-tag { color: var(--teal-hi); }
.day-head .rule { flex: 1; height: 1px; background: var(--line); }
.day-head .ghost {
  font-size: 30px;
  font-weight: 800;
  line-height: .8;
  letter-spacing: -.04em;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
  opacity: .5;
}

/* ---- cards ---- */
.card {
  position: relative;
  border-radius: var(--r-card);
  padding: 11px 14px 10px 15px;
  transition: transform .2s var(--ease), border-color .2s var(--ease), box-shadow .2s var(--ease);
}
.card.shoot { padding: 9px 13px 7px 15px; }
/* Identity sits on the name itself: a subtle tinted box in the client's own
   colour, month-chip style. His pick over the edge rail — the edge kept being
   read as decoration. No --ch (no colour) = no box, plain ink. The card border
   still carries "unverified", so nothing collides. */
.card[style*="--ch"] h2.client .v,
.card[style*="--ch"] h2.client .cn {
  background: hsl(var(--ch) var(--cl-tint-s) var(--cl-tint-l));
  color: hsl(var(--ch) var(--cl-s) var(--cl-l));
  border-radius: 7px;
  padding: 2px 8px;
  margin-left: -8px;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
@media (hover: hover) {
  .card:hover {
    border-color: var(--line-2);
    transform: translateY(-1px);
    box-shadow: var(--glass-in), var(--glass-sh-2);
  }
}
.card.unverified { border-color: var(--rec-line); }
.card.cancelled { opacity: .5; }
.card.cancelled .client {
  text-decoration: line-through;
  text-decoration-color: var(--rec-line);
  text-decoration-thickness: 1px;
}
.card.done { opacity: .58; }
.card.review { border-color: var(--brass-line); }

.card .top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 14px;
}
.card.shoot .top { margin-bottom: 3px; }
.client {
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -.025em;
  line-height: 1.15;
  min-width: 0;
}
/* the heading IS the client field — no duplicate row below, and the unverified
   dot sits on the right so the name always starts at the same x */
h2.client .v { font: inherit; letter-spacing: inherit; }
h2.client input { font: 700 20px/1.15 var(--sans); letter-spacing: -.025em; }
.card.shoot .client { font-size: 17px; line-height: 1.25; }
.card.shoot h2.client input { font: 700 17px/1.25 var(--sans); }
.top-right { flex: none; display: flex; align-items: center; gap: 8px; }

/* ---- the compact shoot card ----
   Three lines and nothing else: whose shoot, when, who is running it. Roughly
   half the height of what this replaced, so a phone shows a working day rather
   than one booking. Crew, location, notes and the exact date moved into the
   drawer — real, but not worth framing every card with. */
.card.shoot .line {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0 7px;
  font-size: 13.5px;
  margin-bottom: 4px;
}
.card.shoot .line .tsep { color: var(--ink-3); }
.card.shoot .tm .v { font-size: 13.5px; white-space: nowrap; }
.card.shoot .ttl { min-width: 0; flex: 1 1 auto; }
.card.shoot .ttl .v { font-size: 13.5px; color: var(--ink-2); }
.card.shoot .ttl::before { content: '·'; margin-right: 7px; color: var(--ink-3); }
.card.shoot .foot { display: flex; align-items: center; gap: 8px; }
.card.shoot .foot .grow { flex: 1; }
/* Who is running it — the one thing that actually varies shoot to shoot. Nine
   shoots in ten are the house crew, so "our team" is set quietly and only the
   exception is given a border and full-contrast ink. A pill shouting OUR TEAM
   on every card would be the same noise the crew and location rows were. */
.runby {
  flex: none;
  cursor: pointer;
  padding: 5px 10px;
  margin-left: -10px;
  border: 1px solid transparent;
  border-radius: var(--r-pill);
}
/* The two ends of this row are a matched pair, so they wear the same
   silkscreen: .runby is in the label rule above exactly as .status is, which
   sets the pill's own line box and makes the two the same height. The .v needs
   .field.runby, not .runby — .field .v comes later in this file at 15px and was
   quietly winning, which is why "CLIENT TEAM" sat half again as large as
   "TENTATIVE" opposite it. */
.field.runby .v { font: inherit; letter-spacing: inherit; text-transform: inherit; }
.runby[data-raw="client"] {
  border-color: var(--line-2);
  background: var(--fill);
  margin-left: 0;
}
.runby[data-raw="client"] .v { color: var(--ink); }
.runby:hover { border-color: var(--line-2); }
/* the tap target is bigger than the ink, without pushing the lines apart */
.card.shoot .line .field { padding: 3px 5px; margin: -3px -5px; border-radius: var(--r-field); }

button.more {
  appearance: none; cursor: pointer;
  background: none; border: 1px solid transparent;
  border-radius: var(--r-pill);
  padding: 7px 9px;
  font: 700 10px/1 var(--sans);
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--muted);
  display: flex; align-items: center; gap: 6px;
  transition: color .2s var(--ease), border-color .2s var(--ease);
}
button.more::after {
  content: '';
  border-left: 3.5px solid transparent;
  border-right: 3.5px solid transparent;
  border-top: 4px solid currentColor;
  transition: transform .2s var(--ease);
}
button.more:hover { color: var(--ink-2); border-color: var(--line-2); }
.card.open button.more::after { transform: rotate(180deg); }
button.verify.tiny { padding: 8px 13px; font-size: 10px; letter-spacing: .13em; }

/* The drawer holds the rest of the shoot. It has to stay lighter than the card
   it hangs off, or opening one card costs a screen again. */
.card.shoot .drawer { display: none; }
.card.open .drawer { display: block; padding-top: 10px; margin-top: 9px; border-top: 1px solid var(--line); }
.card.shoot .drawer .fields { gap: 9px 14px; }
.card.shoot .drawer .field .k { font-size: 9px; margin-bottom: 2px; }
.card.shoot .drawer .field .v { font-size: 13px; }
.card.shoot .drawer .source { margin-top: 10px; }
.card.shoot .drawer .actions { margin-top: 10px; }
.card.shoot .drawer .actions button { padding: 8px 14px; font-size: 10px; }
/* Status is a menu, not a caption. It was styled like the rest of the small
   print and nobody found it, so it now carries a control's outline and a
   caret — the two things that say "this opens". */
.status {
  flex: none;
  cursor: pointer;
  padding: 5px 10px;
  border: 1px solid var(--line-2);
  border-radius: var(--r-pill);
  background: var(--fill);
  transition: border-color .2s var(--ease), background .2s var(--ease);
}
.status:hover { border-color: var(--ink-3); background: var(--glass-2); }
.status .v.st { font: inherit; letter-spacing: inherit; text-transform: inherit; }
.st.tentative { color: var(--brass); }
.st.cancelled { color: var(--rec); }
.st.done { color: var(--teal-hi); }

/* the caret: same mark on the card pill and in the sheet's status column */
.field[data-type="select"] .v::after {
  content: '';
  display: inline-block;
  margin-left: 6px;
  vertical-align: middle;
  border-left: 3.5px solid transparent;
  border-right: 3.5px solid transparent;
  border-top: 4px solid currentColor;
  opacity: .55;
  transition: transform .2s var(--ease);
}
.field[data-type="select"][aria-expanded="true"] .v::after { transform: rotate(180deg); }

/* ---- the pick menu (status + run by) ----
   What replaced the native <select>. That control was the one thing on the
   board wearing the operating system's clothes — a wheel over the whole screen
   on a phone, a grey list on the sheet. This is the board's own glass, holding
   the same pills the cards use, on both surfaces. Fixed to the viewport rather
   than nested in the field, because the sheet scrolls sideways inside a
   clipping box and would cut a menu in half. */
.menu {
  position: fixed;
  z-index: 60;
  /* solid, not glass — see --menu-bg. The gradient and the lit top edge stay,
     so it is still the same material family, just not see-through. */
  background-color: var(--menu-bg);
  background-image: var(--glass);
  border: 1px solid var(--glass-bd);
  box-shadow: var(--glass-in), var(--glass-sh-2);
  padding: 5px;
  border-radius: 14px;
  display: flex;
  flex-direction: column;
  gap: 1px;
  animation: menu-in .16s var(--ease) both;
}
@keyframes menu-in { from { opacity: 0; transform: translateY(-4px); } }
.menu .mi {
  appearance: none;
  cursor: pointer;
  background: none;
  border: 0;
  border-radius: var(--r-pill);
  padding: 10px 13px;
  display: flex;
  align-items: center;
  gap: 9px;
  text-align: left;
  font: 700 10px/1 var(--sans);
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-2);
  transition: background .15s var(--ease), color .15s var(--ease);
}
/* :focus, not :focus-visible — the menu is opened by tap as often as by key,
   and the option you are standing on has to be visible either way */
.menu .mi:hover, .menu .mi:focus { background: var(--fill); color: var(--ink); outline: none; }
.menu .mi .ml { font: inherit; letter-spacing: inherit; }
/* the current pick keeps its tick where the caret was, so the eye lands on the
   same edge it tapped */
.menu .mi.on { color: var(--ink); }
.menu .mi.on::after {
  content: '\2713';
  margin-left: auto;
  padding-left: 12px;
  font-size: 11px;
  color: var(--teal-hi);
}
@media (prefers-reduced-transparency: reduce) {
  .menu { background-image: none; border-color: var(--line-2); }
}

/* the tally light: red = still rolling (unverified) */
.tally {
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--rec);
  box-shadow: 0 0 8px var(--rec-line);
  margin-right: 7px;
  vertical-align: 2px;
  animation: tally 1.6s steps(1) infinite;
}
@keyframes tally { 50% { opacity: .35; } }

/* ---- fields (two-tap edit, shared by cards + sheet) ---- */
.fields { display: grid; grid-template-columns: 1fr 1fr; gap: 11px 14px; }
.fields .field {
  min-width: 0;
  padding: 4px 6px;
  margin: -4px -6px;
  border-radius: var(--r-field);
}
.field { cursor: pointer; transition: background .18s var(--ease); }
.fields .field.wide { grid-column: 1 / -1; }
.field:active, .field.editing { background: var(--teal-tint); }
.field .k { display: block; font-size: 9.5px; margin-bottom: 4px; }
.field .v {
  font-size: 15px;
  font-weight: 500;
  line-height: 1.35;
  font-variant-numeric: tabular-nums;
  /* break long words only when they genuinely cannot fit, never mid-word on
     short values like times or statuses */
  overflow-wrap: break-word;
  word-break: normal;
}
.field .v.empty { color: var(--muted); }
.field input {
  width: 100%;
  appearance: none;
  background: transparent;
  border: 0;
  border-bottom: 1.5px solid var(--teal);
  border-radius: 0;
  outline: none;
  color: var(--ink);
  caret-color: var(--teal-hi);
  font: 500 16px/1.3 var(--sans); /* 16px: iOS zooms the page on focus below this */
  font-variant-numeric: tabular-nums;
  padding: 0 0 2px;
}
.field.saved { animation: saved 1.1s var(--ease); }
@keyframes saved { 0% { background: var(--teal-tint); } }

/* ---- the sheet (desktop week): one glass pane holding the data ---- */
.sheet-wrap { overflow-x: auto; border-radius: var(--r-card); }
table.sheet { width: 100%; border-collapse: collapse; }
.sheet th {
  font: 700 9.5px/1 var(--sans);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: left;
  padding: 13px 14px 11px;
  border-bottom: 1px solid var(--line-2);
  white-space: nowrap;
}
.sheet td {
  border-top: 1px solid var(--line);
  padding: 10px 14px;
  font-size: 13px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  vertical-align: middle;
}
.sheet tr.day-row td {
  font: 700 10px/1 var(--sans);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-2);
  background: var(--fill);
  padding: 9px 14px 8px;
}
.sheet td.field { padding: 0; }
.sheet td.field > .v, .sheet td.field > input {
  display: block;
  padding: 10px 14px;
  font-size: 13px;
  width: 100%;
}
.sheet td.field > input { padding-bottom: 9px; }
.sheet .v.empty { color: transparent; } /* blank cell reads as a sheet; tap still edits */
@media (hover: hover) {
  .sheet tbody tr.row:hover td { background: var(--glass-2); }
}
/* Short-value columns must never break mid-word ("10:00" -> "10:0 / 0"). */
.sheet .c-date, .sheet .c-time, .sheet .c-status { white-space: nowrap; }
.sheet .c-date .v, .sheet .c-time .v, .sheet .c-status .v { word-break: normal; white-space: nowrap; }
.sheet .c-date { width: 74px; }
.sheet .c-time { width: 88px; }
.sheet .c-status { width: 96px; }
/* Client names all start at the same x — the unverified dot moved to the right
   edge of the row so nothing indents the name. */
.sheet .c-client .v {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: -.02em;
  white-space: nowrap;
}
/* the same identity mark as the card rail, sized for a row */
.sheet .c-client .v::before {
  content: '';
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 50%;
  margin-right: 8px;
  vertical-align: 1px;
  background: hsl(var(--ch) var(--cl-s) var(--cl-l));
}
.sheet .c-run { width: 104px; white-space: nowrap; }
.sheet .c-run .v { color: var(--ink-2); white-space: nowrap; }
/* "1st Half" and "2nd Half" are the same length but "nd" is wider than "st",
   which put one of them over the wrap boundary. Hold the column open. */
.sheet .c-notes { min-width: 84px; }
.sheet tr.cancelled td { opacity: .5; }
.sheet tr.cancelled .c-client .v { text-decoration: line-through; text-decoration-color: var(--rec-line); }
.sheet .c-act {
  width: 108px;
  text-align: right;
  padding-right: 10px;
  white-space: nowrap;
}
.sheet .c-act .tally { margin-right: 8px; vertical-align: middle; }
button.rowverify, button.rowremove {
  appearance: none; cursor: pointer;
  font: 700 13px/1 var(--sans);
  color: var(--teal-hi);
  background: var(--teal-tint);
  border: 1px solid var(--teal-line);
  border-radius: var(--r-pill);
  width: 34px; height: 30px;
  transition: transform .15s var(--ease), background .2s var(--ease), color .2s var(--ease), border-color .2s var(--ease);
}
button.rowverify:hover { background: var(--teal-line); }
button.rowverify:active, button.rowremove:active { transform: scale(.94); }
/* remove sits quiet next to verify until it is hovered or armed */
button.rowremove {
  margin-left: 6px;
  font-size: 16px;
  color: var(--muted);
  background: none;
  border-color: var(--line-2);
}
button.rowremove:hover { color: var(--rec); border-color: var(--rec-line); }
button.rowremove.confirming {
  color: var(--rec);
  background: var(--rec-tint);
  border-color: var(--rec);
  animation: armed 1.4s steps(1) infinite;
}
@keyframes armed { 50% { opacity: .55; } }

/* ---- month grid ---- */
.month-head { display: flex; align-items: center; gap: 6px; padding: 0 2px 6px; }
.month-head .mt {
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -.035em;
  margin: 0 8px;
  min-width: 168px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
button.mnav {
  appearance: none; cursor: pointer;
  border-radius: var(--r-pill);
  color: var(--ink-2);
  font: 500 16px/1 var(--sans);
  width: 44px; height: 36px;
  transition: color .2s var(--ease), border-color .2s var(--ease), transform .15s var(--ease);
}
button.mnav:hover { color: var(--ink); border-color: var(--line-2); }
button.mnav:active { transform: scale(.94); }

.dow-row { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 4px; padding: 0 2px; }
.dow { text-align: center; font-size: 9px; padding: 5px 0; }
.mgrid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 4px; }
/* 35+ cells: tinted fill and hairline, no per-cell blur (the grid is the pane).
   Padding and gaps are tight on a phone because every pixel taken here comes
   straight out of the width the client name has to fit in. */
.mcell {
  appearance: none;
  font: inherit;
  color: inherit;
  text-align: left;
  background: var(--glass);
  border: 1px solid var(--line);
  border-radius: var(--r-field);
  min-height: 58px;
  padding: 4px 4px 5px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  cursor: pointer;
  transition: border-color .2s var(--ease), background .2s var(--ease), transform .15s var(--ease);
}
.mcell.blank { background: none; border-color: transparent; pointer-events: none; }
.mcell:hover { border-color: var(--line-2); }
.mcell:active { transform: scale(.98); }
.mcell.sel { border-color: var(--teal-line); background: var(--teal-tint); }
.mnum {
  font: 700 11.5px/1 var(--sans);
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
}
.mcell.today .mnum { color: var(--teal-hi); font-weight: 800; }
/* The name, at every width. This used to collapse to anonymous dots on a phone,
   which loses the only thing the month view is for. The chip is tinted and
   inked in the client's own hue; unverified is a red ring around it, so red
   keeps meaning exactly one thing here as it does everywhere else. */
.mchip {
  display: block;
  font: 700 8.5px/1.3 var(--sans);
  letter-spacing: -.01em;
  color: hsl(var(--ch) var(--cl-s) var(--cl-l));
  background: hsl(var(--ch) var(--cl-tint-s) var(--cl-tint-l));
  border-radius: 4px;
  padding: 2px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.mchip.unv { box-shadow: 0 0 0 1px var(--rec-line); }
.mchip.cancelled { text-decoration: line-through; opacity: .6; }
.mmore { font: 700 8.5px/1.25 var(--sans); color: var(--muted); background: none; padding: 1px 3px; }
.mhint { text-align: center; padding: 18px 0 4px; }
@media (min-width: 700px) {
  .dow-row, .mgrid { gap: 5px; }
  .mcell { min-height: 96px; padding: 6px 7px; gap: 4px; }
  .mchip { font-size: 10.5px; padding: 3px 6px; border-radius: 5px; }
  .mmore { font-size: 10px; padding: 1px 6px; }
}

/* ---- client colour swatches (in every card's drawer) ----
   Finder-label idiom: a fixed row, one tap, it sticks to the client. The row
   itself is designed here (hues that clear teal/brass/red); which client wears
   which swatch is the user's, stored on the client row. */
.swatches { margin-top: 12px; }
.swatches .k { display: block; margin-bottom: 7px; }
.card.shoot .drawer .swatches .k { font-size: 9px; }
/* Twelve hues plus "none" — seven to a row so the wrap is a decision, not an
   accident of width, and both rows start at the same left edge as the labels. */
.sw-row { display: grid; grid-template-columns: repeat(7, 26px); gap: 10px; justify-content: start; }
button.sw {
  appearance: none;
  cursor: pointer;
  width: 26px; height: 26px;
  border-radius: 50%;
  border: 1px solid var(--glass-bd);
  background: hsl(var(--ch) var(--cl-s) var(--cl-l));
  transition: transform .15s var(--ease);
}
button.sw:active { transform: scale(.88); }
/* the ring marks the explicit pick; the hash placeholder never gets one */
button.sw.on { outline: 2px solid var(--ink-2); outline-offset: 2px; }
button.sw.none { background: none; border-color: var(--line-2); position: relative; }
button.sw.none::after {
  content: '';
  position: absolute;
  left: 4px; right: 4px; top: 50%;
  height: 1.5px;
  background: var(--muted);
  transform: rotate(-45deg);
}

/* ---- source message (whatsapp) ---- */
.source { margin-top: 14px; }
.source summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 3px 0;
  -webkit-user-select: none;
  user-select: none;
  transition: color .2s var(--ease);
}
.source summary::-webkit-details-marker { display: none; }
.source summary::before {
  content: '\203A';
  font-size: 13px;
  line-height: 1;
  letter-spacing: 0;
  color: var(--muted);
  transition: transform .2s var(--ease);
}
.source[open] summary::before { transform: rotate(90deg); }
.source summary:hover { color: var(--ink-2); }
.source blockquote {
  margin: 8px 0 2px 3px;
  padding: 2px 0 2px 12px;
  border-left: 2px solid var(--teal-line);
  font-size: 13.5px;
  font-weight: 400;
  line-height: 1.55;
  color: var(--ink-2);
  white-space: pre-wrap;
}

.conf.high { color: var(--teal-hi); }
.conf.medium { color: var(--brass); }
.conf.low { color: var(--rec); }

/* ---- actions ---- */
/* Three of these have to sit on one line at 402px — "mark verified" wrapping
   onto two lines is the tell that the padding was set on a desktop. */
.actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
.actions button { white-space: nowrap; }
/* verify and small are named here as well as inside .actions because the
   compact card puts a verify button in its foot row, outside any .actions */
.actions button, button.verify, button.small {
  appearance: none;
  cursor: pointer;
  font: 700 11px/1 var(--sans);
  letter-spacing: .14em;
  text-transform: uppercase;
  border-radius: var(--r-pill);
  padding: 11px 15px;
  transition: transform .15s var(--ease), background .2s var(--ease), color .2s var(--ease);
}
.actions button:active, button.verify:active, button.small:active { transform: scale(.98); }
button.verify {
  /* sized to its label, not stretched across the card */
  color: var(--teal-hi);
  background: var(--teal-tint);
  border: 1px solid var(--teal-line);
  padding: 10px 17px;
}
button.verify:hover { background: var(--teal-line); }
button.small {
  color: var(--ink-2);
  background: none;
  border: 1px solid var(--line-2);
}
button.small:hover { color: var(--ink); border-color: var(--ink-3); }
/* remove is destructive — muted until armed, then unmistakably red */
button.small.danger { color: var(--muted); }
button.small.danger:hover { color: var(--rec); border-color: var(--rec-line); }
button.small.danger.confirming {
  color: var(--rec);
  background: var(--rec-tint);
  border-color: var(--rec);
}
button[disabled] { opacity: .45; pointer-events: none; }

/* one pinned day, opened from verify's "change" */
.focus-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-bottom: 4px;
}
.focus-bar button.small {
  appearance: none; cursor: pointer;
  font: 700 10px/1 var(--sans);
  letter-spacing: .14em; text-transform: uppercase;
  border-radius: var(--r-pill);
  padding: 9px 14px;
  color: var(--ink-2); background: none;
  border: 1px solid var(--line-2);
}
.focus-bar button.small:hover { color: var(--ink); border-color: var(--ink-3); }

/* verified settles: one teal pulse after the tap */
.card.settle, tr.settle td { animation: settle 1.1s var(--ease); }
@keyframes settle { 0% { background: var(--teal-tint); } }
.card.settle { animation-name: settlecard; }
@keyframes settlecard {
  0% { border-color: var(--teal-line); box-shadow: var(--glass-in), 0 0 26px var(--teal-tint); }
}

/* ---- verify tab ---- */
.sect { display: flex; align-items: center; gap: 12px; margin: 12px 4px 2px; }
.sect:first-child { margin-top: 0; }
.sect .rule { flex: 1; height: 1px; background: var(--line); }
.sect .n { color: var(--ink-2); }
.sect .n.rec { color: var(--rec); }
.sect.brass .t { color: var(--brass); }

.sect.rec-sect .t { color: var(--rec); }

/* tentative: pencilled in, waiting on a yes or a no */
.card.tentative { border-color: var(--brass-line); }
.card.tentative .sub { color: var(--brass); }
.pencil {
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--brass);
  margin-right: 7px;
  vertical-align: 2px;
}

.sub { display: block; margin-bottom: 8px; }
.sub .ok { color: var(--teal-hi); }
.sub .aged { color: var(--rec); }
.card .sub + .client { margin-bottom: 12px; }

.diffs { display: flex; flex-direction: column; gap: 7px; margin: 12px 0 2px; }
.diff {
  display: flex;
  align-items: baseline;
  gap: 9px;
  flex-wrap: wrap;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}
.diff .dk { min-width: 54px; }
.diff s { color: var(--muted); text-decoration-color: var(--muted); }
.diff .arrow { color: var(--teal-hi); font-size: 13px; }
.diff .dv { color: var(--ink); font-weight: 700; }

.reason {
  font-size: 16px;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: -.015em;
  color: var(--brass);
  margin-bottom: 6px;
}

/* ---- headline: the loud line on wrap + empty screens ---- */
.wrap-banner { text-align: center; padding: 36px 16px 24px; }
.headline {
  font-size: 30px;
  font-weight: 800;
  letter-spacing: -.04em;
  line-height: 1.05;
  margin-bottom: 12px;
}
.empty-state { text-align: center; padding: 76px 20px; }
.empty-state .headline { font-size: 26px; color: var(--ink-2); }

/* ---- notice ---- */
#notice {
  position: fixed;
  left: 50%; bottom: calc(20px + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  z-index: 50;
  white-space: nowrap;
  border-color: var(--rec-line);
  color: var(--ink);
  font: 600 12px/1 var(--sans);
  letter-spacing: .05em;
  padding: 13px 20px;
  border-radius: var(--r-pill);
  box-shadow: var(--glass-in), var(--glass-sh-2);
}
#notice.ok { border-color: var(--teal-line); }
#notice.bad { border-color: var(--rec-line); color: var(--rec); }

/* ---- share the schedule -------------------------------------------------
   The header icon does the work and needs no label, because the masthead
   directly above it already names the span it sends. The only other share is
   on a day picked inside the month grid — the one span the header cannot
   reach — and it is a word in that day's own header row, not a slab under it. */
.daylink {
  appearance: none; background: none; border: 0; cursor: pointer;
  flex: 0 0 auto;
  padding: 6px 8px;
  margin: -6px 0;
  color: var(--ink-3);
  font: 700 10px/1 var(--sans);
  letter-spacing: .16em;
  text-transform: uppercase;
  transition: color .2s var(--ease);
}
.daylink:active { color: var(--teal-hi); }
@media (hover: hover) { .daylink:hover { color: var(--ink-2); } }

/* ---- billing screen ----------------------------------------------------
   Behind the receipt icon, not a tab. Same material as the board — this is the
   same instrument, not a settings panel bolted on. Type stays on the six-step
   scale; the only thing here that gets weight is a client's name and an
   amount, because those are what you scan for. */
.billing .card { padding: 14px 15px; }
.billing .actions { margin-top: 10px; }

.bempty { color: var(--ink-2); font: 400 14px/1.5 var(--sans); }

.binv .bi-top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.bi-no { font: 700 15px/1.2 var(--sans); font-variant-numeric: tabular-nums; }
.bi-amt { font: 700 15px/1.2 var(--sans); font-variant-numeric: tabular-nums; white-space: nowrap; }
.bi-sub { margin-top: 3px; }

/* A voided invoice stays on the list — the number is burned, the row says so.
   Quietened, struck, and labelled in the red the board already uses for
   "this is not live"; the links stay because the stamped documents are still
   the record of what was cancelled. */
.binv.bdead { opacity: .62; }
.binv.bdead .bi-no s { text-decoration-thickness: 1.5px; }
.bvoid-mark {
  font: 600 10px/1 var(--sans);
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--rec);
}

/* The invoice links are real anchors, not buttons: the admin needs to
   long-press one and copy it into a WhatsApp message to the client. But the
   shared action styles are all written `button.verify` / `button.small`, so an
   anchor was inheriting none of them and rendering as a 22px bare link —
   measured, half the 44px a thumb needs. These give the anchors the same body
   and the same hit area. */
.billing .actions { display: flex; flex-wrap: wrap; gap: 8px; }
.billing .actions a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  font: 700 11px/1 var(--sans);
  letter-spacing: .14em;
  text-transform: uppercase;
  border-radius: var(--r-pill);
  padding: 0 17px;
  transition: transform .15s var(--ease), background .2s var(--ease), color .2s var(--ease);
}
.billing .actions a:active { transform: scale(.98); }
.billing .actions a.verify { color: var(--teal-hi); background: var(--teal-tint); border: 1px solid var(--teal-line); }
.billing .actions a.small { color: var(--ink-2); border: 1px solid var(--line-2); }
@media (hover: hover) {
  .billing .actions a.verify:hover { background: var(--teal-line); }
  .billing .actions a.small:hover { color: var(--ink); border-color: var(--ink-3); }
}
/* `edit` and `cancel` are 34px from the shared button rule, which is fine
   buried in a card's drawer and not fine as this screen's own controls. */
.billing .actions button, .billing .bp-top button { min-height: 44px; }

button.badd {
  width: 100%;
  text-align: left;
  cursor: pointer;
  color: var(--teal-hi);
  font: 700 12px/1 var(--sans);
  letter-spacing: .1em;
  text-transform: uppercase;
  padding: 18px 15px;
  border-style: dashed;
}

.bp-top { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.bp-name { font: 700 15px/1.25 var(--sans); }
.bp-sub { margin-top: 3px; }
.bp-none { margin-top: 10px; color: var(--ink-3); }
.bp-clients { margin-top: 11px; display: flex; flex-direction: column; gap: 7px; }

/* One board client per row: who it is, who it bills to, what it costs an hour. */
.brow {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 7px 9px;
  align-items: center;
  padding: 9px 10px;
  background: var(--fill);
  border-radius: var(--r-field);
}
.bname { font: 600 13px/1.2 var(--sans); }
.bsel, .brate { grid-column: 1 / -1; }
.bsel {
  appearance: none;
  width: 100%;
  font: 500 13px/1 var(--sans);
  color: var(--ink);
  background: transparent;
  border: 1px solid var(--line-2);
  border-radius: var(--r-field);
  padding: 9px 10px;
  min-height: 44px;   /* a thumb, not a cursor */
}
.brate {
  display: flex; align-items: center; gap: 6px;
  font: 500 13px/1 var(--sans); color: var(--ink-2);
}
.brate input {
  flex: 1 1 auto; min-width: 0;
  font: 500 13px/1 var(--sans);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  background: transparent;
  border: 1px solid var(--line-2);
  border-radius: var(--r-field);
  padding: 9px 10px;
  min-height: 44px;   /* a thumb, not a cursor */
}
/* Remove a board client. Quiet until touched — it shares the row's top line
   with the name, and arms in place (two-tap) like every other removal here. */
.bx {
  grid-column: 2; grid-row: 1;
  justify-self: end;
  min-width: 40px; min-height: 40px;
  margin: -8px -8px -8px 0;
  font: 500 17px/1 var(--sans);
  color: var(--muted);
  background: transparent; border: 0; border-radius: 8px;
  cursor: pointer;
}
.bx:hover, .bx[data-armed='1'] { color: var(--rec); }
.bx[data-armed='1'] { font: 600 11px/1 var(--sans); letter-spacing: .08em; text-transform: uppercase; }

@media (min-width: 560px) {
  .brow { grid-template-columns: 1fr 1fr auto auto; }
  .bsel, .brate { grid-column: auto; }
  .brate { width: 132px; }
  .bx { grid-column: auto; grid-row: auto; }
}

/* The add/edit form. Labels are visible, never placeholder-only — this is the
   one screen where a wrong character becomes a wrong tax on a real document. */
.bform { display: flex; flex-direction: column; gap: 11px; }
.bf { display: flex; flex-direction: column; gap: 5px; }
.bf input, .bf textarea {
  font: 500 15px/1.4 var(--sans);   /* 15px: anything smaller and iOS zooms the page on focus */
  color: var(--ink);
  background: var(--fill);
  border: 1px solid var(--line-2);
  border-radius: var(--r-field);
  padding: 10px 11px;
  width: 100%;
  min-height: 42px;
  resize: vertical;
}
.bf input[name="gstin"] { font-variant-numeric: tabular-nums; letter-spacing: .04em; text-transform: uppercase; }
.bf input:focus, .bf textarea:focus { outline: 2px solid var(--teal); outline-offset: 1px; border-color: transparent; }
/* What the GSTIN turned out to mean. It answers as you type, so a mistyped
   state is caught here rather than on a client's invoice. */
.bderived { color: var(--ink-2); margin-top: -4px; }
.bderived.bad { color: var(--rec); }

/* ---- entrance (tab switch only, not the 60s refresh) ---- */
.enter > *, .enter .col > * { animation: rise .4s var(--ease) both; }
.enter > *:nth-child(2), .enter .col > *:nth-child(2) { animation-delay: .05s; }
.enter > *:nth-child(3), .enter .col > *:nth-child(3) { animation-delay: .1s; }
.enter > *:nth-child(n+4), .enter .col > *:nth-child(n+4) { animation-delay: .15s; }
@keyframes rise { from { opacity: 0; transform: translateY(8px); } }

/* ---- focus + reduced motion ---- */
:where(button, a, .field, summary, .hero[data-hero]):focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation: none !important;
    transition: none !important;
  }
}
