/* Deliberately small. This is a dashboard for two people to glance at, not an
   app anyone works in all day: the writing surface is the MCP server. */
:root {
  --bg: #fbfaf8;
  --surface: #fff;
  --surface-2: #f5f1ea;
  --border: #e4ded4;
  --border-soft: #efeae2;
  --ink: #1c1a17;
  --muted: #7a736a;
  --accent: #ff5500;
  --risk: #9e2b25;
  --warn: #a8730a;
  /* Contact that actually happened. Deliberately not the accent: this is
     semantic, and the orange has to stay the one colour that means "us". */
  --live: #2f6f5e;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #141311; --surface: #1c1a17; --surface-2: #232019;
    --border: #322e28; --border-soft: #2a2721;
    --ink: #eeeae3; --muted: #968e83; --accent: #ff7736;
    --risk: #e08279; --warn: #d3a24a; --live: #6fbfa6;
  }
}
* { box-sizing: border-box; }
body {
  margin: 0; background: var(--bg); color: var(--ink);
  font: 15px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
}
header {
  display: flex; align-items: center; gap: 20px;
  padding: 14px 20px; border-bottom: 1px solid var(--border); background: var(--bg);
  /* viewport-fit=cover in the head lets the page paint under the notch and the
     home indicator, which is what makes the header background reach the top
     edge. The inset has to be added back by hand or the tabs sit under the
     camera in landscape. max(), not +, so the normal padding is the floor. */
  padding-left: max(20px, env(safe-area-inset-left));
  padding-right: max(20px, env(safe-area-inset-right));
}
h1 { font-size: 17px; margin: 0; letter-spacing: -0.01em; }
h1::after { content: "."; color: var(--accent); }
nav { display: flex; gap: 4px; }
nav button {
  background: none; border: 1px solid transparent; color: var(--muted);
  padding: 5px 12px; border-radius: 5px; cursor: pointer; font: inherit; font-size: 14px;
}
nav button.active { color: var(--ink); border-color: var(--border); background: var(--surface); }
nav button:focus-visible, #signin:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
#search {
  margin-left: auto; width: 200px; padding: 5px 10px; font: inherit; font-size: 13px;
  color: var(--ink); background: var(--surface);
  border: 1px solid var(--border); border-radius: 5px;
}
#search::placeholder { color: var(--muted); }
#search:focus-visible { outline: 2px solid var(--accent); outline-offset: -1px; }
/* The input already carries margin-left:auto, so the count and name sit
   directly after it rather than being pushed to the far edge. */
#search-count { font-size: 12px; font-family: var(--mono); white-space: nowrap; }
#search[hidden] + #search-count + #who { margin-left: auto; }
#who { color: var(--muted); font-size: 13px; }
main {
  padding: 20px; max-width: 1200px; margin: 0 auto;
  padding-left: max(20px, env(safe-area-inset-left));
  padding-right: max(20px, env(safe-area-inset-right));
  padding-bottom: calc(20px + env(safe-area-inset-bottom));
}
#login { text-align: center; padding: 80px 20px; }
#signin {
  background: var(--accent); color: #fff; border: 0; border-radius: 6px;
  padding: 10px 22px; font: inherit; font-weight: 600; cursor: pointer;
}
.err { color: var(--risk); }
table { width: 100%; border-collapse: collapse; background: var(--surface);
        border: 1px solid var(--border); border-radius: 6px; overflow: hidden; }
th, td { text-align: left; padding: 9px 13px; border-bottom: 1px solid var(--border); font-size: 14px; vertical-align: top; }
th { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); font-weight: 600; }
tr:last-child td { border-bottom: 0; }
td.muted, .muted { color: var(--muted); }
.pill { display: inline-block; padding: 1px 7px; border-radius: 10px; font-size: 12px; border: 1px solid; }
.pill.due { color: var(--risk); border-color: var(--risk); }
.pill.stale { color: var(--warn); border-color: var(--warn); }
.pill.ok { color: var(--muted); border-color: var(--border); }
.alert {
  border: 1px solid var(--border); border-left: 3px solid var(--risk);
  background: var(--surface); padding: 11px 15px; border-radius: 5px; margin-bottom: 12px; font-size: 14px;
}
.alert.warn { border-left-color: var(--warn); }

/* Enrolment. Collapsed behind a <details> because it is a first-run and
   lost-device path, not something anyone does twice. */
#enrol { max-width: 340px; margin: 28px auto 0; text-align: left; }
#enrol summary { cursor: pointer; color: var(--muted); font-size: 14px; }
#enrol summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
#enrol p { font-size: 13px; }
#enrol-form { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
#enrol-form input {
  padding: 8px 11px; border: 1px solid var(--border); border-radius: 5px;
  background: var(--surface); color: var(--ink); font: inherit; font-size: 14px;
}
#enrol-form input:focus-visible { outline: 2px solid var(--accent); outline-offset: -1px; }
#enrol-form button {
  background: var(--accent); color: #fff; border: 0; border-radius: 5px;
  padding: 9px 14px; font: inherit; font-weight: 600; cursor: pointer;
}

/* ------------------------------------------------------------- recent --- */
/* The recency view. Each age band is a separate card with its own header
   rather than a section inside one long table: the eye should land on a band
   before it lands on a row. Nothing here collapses except an account's
   timeline, because a shut band and an empty band look identical, and an empty
   band is the most informative thing this view can show. */

.controls { border: 1px solid var(--border); border-radius: 6px; background: var(--surface); overflow: hidden; }
.toolbar { display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
           padding: 11px 15px; border-bottom: 1px solid var(--border); background: var(--bg); }
.toolbar-label { font-family: var(--mono); font-size: 11px; letter-spacing: 0.07em;
                 text-transform: uppercase; color: var(--muted); }
.seg { display: flex; border: 1px solid var(--border); border-radius: 5px; overflow: hidden; }
.seg button { font: inherit; font-size: 13px; padding: 4px 12px; border: 0;
              background: var(--surface); color: var(--muted); cursor: pointer; }
.seg button + button { border-left: 1px solid var(--border); }
.seg button[aria-pressed="true"] { background: var(--ink); color: var(--bg); }
.seg button:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.count-note { margin-left: auto; font-size: 13px; color: var(--muted); }

.legend { display: flex; flex-wrap: wrap; gap: 5px 18px; padding: 10px 15px;
          font-size: 12.5px; color: var(--muted); }
.legend span { display: inline-flex; align-items: center; gap: 7px; }

/* Shape carries whether the touch was live, fill carries direction. Two
   channels rather than colour alone, so the strip stays readable to anyone who
   cannot separate the green from the grey. */
.m { display: inline-block; width: 9px; height: 9px; border-radius: 50%;
     border: 1.5px solid var(--muted); background: transparent; flex: none; }
.m.live { border-radius: 2px; transform: rotate(45deg); width: 10px; height: 10px; border-color: var(--live); }
.m.inb { background: var(--muted); }
.m.live.inb { background: var(--live); }
.m.int { width: 6px; height: 6px; border-radius: 1px; transform: none;
         border: 1px solid var(--muted); background: var(--muted); opacity: 0.7; }

.board { display: flex; flex-direction: column; gap: 26px; margin-top: 20px; }
.group-head { display: flex; align-items: baseline; gap: 10px; padding: 0 2px 8px; }
.group-title { font-weight: 600; font-size: 15px; letter-spacing: -0.012em; }
.group-range { font-family: var(--mono); font-size: 11px; color: var(--muted);
               padding: 1px 6px; border: 1px solid var(--border); border-radius: 4px;
               background: var(--surface); white-space: nowrap; }
.group-n { margin-left: auto; font-family: var(--mono); font-size: 11px;
           letter-spacing: 0.05em; text-transform: uppercase; color: var(--muted);
           font-variant-numeric: tabular-nums; }
.group-card { border: 1px solid var(--border); border-radius: 6px;
              background: var(--surface); overflow: hidden; }
.group.empty .group-head { opacity: 0.6; }
.group.empty .group-card { background: transparent; border-style: dashed; }
.group-empty { padding: 12px 15px; font-size: 13px; color: var(--muted); margin: 0; }

.row { border-bottom: 1px solid var(--border-soft); }
.group-card .row:last-child { border-bottom: 0; }
.row-head { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr) 92px 116px 20px;
            align-items: center; gap: 12px; width: 100%; text-align: left; font: inherit;
            color: var(--ink); background: var(--surface); border: 0; padding: 11px 15px; cursor: pointer; }
.row:not([data-open="true"]) .row-head:hover { background: var(--surface-2); }
.row-head:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* The open row and its detail stay on --surface. An expanded account is not a
   different kind of surface, and tinting it made the timeline read as a modal
   dropped on top of the list rather than part of the row. The hairline below
   does the separating. */
.row[data-open="true"] .row-head { background: var(--surface); }
.row-head .chev { color: var(--muted); font-size: 10px; justify-self: end;
                  transform: rotate(-90deg); transition: transform 0.14s ease; }
.row[data-open="true"] .row-head .chev { transform: none; }

.co { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.co-name { font-weight: 600; font-size: 14px; letter-spacing: -0.008em; }
.co-deal { font-size: 12.5px; color: var(--muted); overflow: hidden;
           text-overflow: ellipsis; white-space: nowrap; }
.co-deal .stage { font-family: var(--mono); font-size: 11px; }

.chips { display: flex; flex-wrap: wrap; gap: 4px; }
.chip { font-family: var(--mono); font-size: 10.5px; padding: 1px 6px; border-radius: 4px;
        border: 1px solid var(--border); color: var(--muted); background: var(--bg); white-space: nowrap; }
.chip[data-rel="customer"], .chip[data-rel="pilot"] { color: var(--live); border-color: var(--live); }
.chip[data-rel="partner"], .chip[data-rel="advisor"] { color: var(--accent); border-color: var(--accent); }

.since { font-family: var(--mono); font-variant-numeric: tabular-nums;
         display: flex; flex-direction: column; gap: 1px; }
.since b { font-size: 13.5px; font-weight: 500; }
.since span { font-size: 10.5px; color: var(--muted); }
.since.none b { color: var(--muted); font-size: 12px; }

.pill.dormant { color: var(--muted); border-color: var(--border); background: var(--bg); }
.pill.blocked { color: var(--ink); border-color: var(--border); }
.pill.never { color: var(--warn); border-color: var(--warn); }

/* Expanded: one shared twelve-month axis across every row, so two open rows
   can be compared directly. Recent events clump against the right edge as a
   result, which is why the plain-text list underneath exists. */
.detail { display: none; padding: 4px 15px 16px; border-top: 1px solid var(--border-soft); }
.row[data-open="true"] .detail { display: block; }
.strip-wrap { position: relative; padding-top: 8px; }
.axis { position: relative; height: 15px; border-bottom: 1px solid var(--border); }
.axis .tick { position: absolute; top: 0; bottom: 0; border-left: 1px solid var(--border-soft); }
.axis .tick i { position: absolute; bottom: 1px; left: 4px; font-family: var(--mono);
                font-size: 9.5px; font-style: normal; color: var(--muted); white-space: nowrap; }
.axis .now { position: absolute; top: 0; bottom: -60px; right: 0;
             border-left: 1.5px dashed var(--accent); opacity: 0.5; }
.lane { position: relative; height: 28px; }
.lane.internal { height: 22px; }
.lane-track { position: absolute; inset: 0; }
.lane.internal .lane-track::before { content: ""; position: absolute; left: 0; right: 0; top: 50%;
                                     border-top: 1px dotted var(--border); }
.mk { position: absolute; top: 50%; padding: 0; border: 0; background: none; cursor: pointer;
      transform: translate(-50%, -50%); line-height: 0; z-index: 1; }
.mk:hover, .mk:focus-visible { z-index: 5; outline: none; }
.mk:hover .m, .mk:focus-visible .m { box-shadow: 0 0 0 3px var(--surface), 0 0 0 4px var(--accent); }
/* Widens the hit area without widening the marker, which has to stay small
   enough to be honest about where on the axis it sits. */
.mk::after { content: ""; position: absolute; inset: -7px; }

.tip { position: absolute; z-index: 20; max-width: 330px; min-width: 180px;
       background: var(--ink); color: var(--bg); border-radius: 6px; padding: 8px 11px;
       font-size: 12.5px; line-height: 1.45; pointer-events: none; opacity: 0;
       transition: opacity 0.1s ease; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25); }
.tip[data-show="true"] { opacity: 1; }
.tip .t-when { font-family: var(--mono); font-size: 10.5px; text-transform: uppercase;
               letter-spacing: 0.05em; opacity: 0.6; display: block; margin-bottom: 2px; }
.tip .t-who { display: block; margin-top: 4px; font-size: 11.5px; opacity: 0.7; }
.tip .t-flag { display: block; margin-top: 4px; font-size: 11.5px; color: var(--accent); }

.recent-list { margin-top: 12px; border-top: 1px solid var(--border); }
.recent-list h4 { margin: 10px 0 6px; font-family: var(--mono); font-size: 10.5px;
                  letter-spacing: 0.07em; text-transform: uppercase; color: var(--muted); font-weight: 500; }
.ev { display: grid; grid-template-columns: 62px 14px minmax(0, 1fr); gap: 9px;
      align-items: start; padding: 3px 0; font-size: 13px; line-height: 1.5; }
/* Right-aligned so the months line up: the day is one digit or two, and
   left-aligning leaves "4 Aug" and "15 Jul" ragged down the column. */
.ev .d { font-family: var(--mono); font-size: 11.5px; color: var(--muted);
         padding-top: 3px; text-align: right; font-variant-numeric: tabular-nums; }
/* Centred in both axes rather than offset by a fixed padding. The markers are
   three different sizes (6px internal square, 9px circle, 10px diamond), so
   any fixed offset puts their centres in three different places, horizontally
   because they are left-aligned in the column and vertically because the
   padding is measured to their tops. 1.5em is the first text line's box, so a
   marker lands on the middle of the line it belongs to. */
.ev .g { display: flex; align-items: center; justify-content: center; height: 1.5em; }
.ev.int .s { color: var(--muted); }

@media (max-width: 760px) {
  .row-head { grid-template-columns: minmax(0, 1fr) 88px 20px; }
  .row-head .chips, .row-head .pill { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .chev, .tip { transition: none; }
}

/* Local-only diagnostic under the sign-in button. Never rendered in
   production: the route that feeds it 404s off a development host. */
#login-hint {
  max-width: 460px; margin: 24px auto 0; text-align: left;
  border: 1px solid var(--border); border-left: 2px solid var(--warn);
  border-radius: 5px; background: var(--surface); padding: 13px 16px;
}
#login-hint h4 { margin: 0 0 6px; font-size: 13px; font-weight: 600; }
#login-hint p { margin: 0 0 8px; font-size: 13px; color: var(--muted); }
#login-hint ol { margin: 0; padding-left: 18px; font-size: 13px; }
#login-hint li { margin-bottom: 5px; }
#login-hint code {
  font-family: var(--mono); font-size: 12px; background: var(--bg);
  border: 1px solid var(--border); border-radius: 3px; padding: 1px 4px;
}

/* --------------------------------------------------------------- copy --- */
/* Atlas is read-only: a change means describing the row to the agent. These copy
   a label plus the prefixed id, so the message names the thing unambiguously
   without anyone transcribing 32 hex characters by hand. */

.sr {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}
.copy {
  border: 0; background: none; padding: 3px; margin: 0; cursor: pointer;
  color: var(--muted); border-radius: 4px; line-height: 0;
  /* Hidden by opacity, not display, so revealing one never moves the row. */
  opacity: 0; transition: opacity 0.12s ease, color 0.12s ease;
}
.copy .ic { width: 15px; height: 15px; display: block; }
tr:hover .copy, .row-line:hover .copy, .copy:focus-visible { opacity: 1; }
.copy:hover { color: var(--ink); background: var(--surface-2); }
.copy:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.copy.done { opacity: 1; color: var(--live); }
.copy.failed { opacity: 1; color: var(--risk); }
/* Nothing hovers on a touch screen, so the button has to be visible up front. */
@media (hover: none) { .copy { opacity: 0.5; } }

/* The Recent row header is itself a button, so the copy control cannot nest
   inside it. They become siblings on one line instead. */
.row-line { display: flex; align-items: stretch; }
.row-line .row-head { flex: 1; min-width: 0; }
.row-line .copy { align-self: center; margin-right: 12px; }

/* Table cells: shrink to the button and keep it off the right edge. */
td:has(> .copy), th:has(> .sr) { width: 1%; padding-left: 4px; text-align: right; }

/* ---------------------------------------------------------- dashboard --- */
/* The two series colours are the only ones in the app that were computed
   rather than chosen. Atlas's --live teal fails the chroma floor at 0.072 and
   reads grey when it carries a fill, so the series green is a step up from it.
   Validated against both surfaces: light #00805f/#ff5500 on #fbfaf8, dark
   #0f9670/#ea6420 on #141311, clearing CVD, normal-vision and 3:1 contrast.
   Changing either one means re-validating the pair, not eyeballing it.

   Every other chart is single-hue on purpose. The country and stage names sit
   on the axis beside their bars, so a colour per row would encode nothing the
   row does not already say. */
:root {
  --series-live: #00805f;
  --series-msg: #ff5500;
  --grid: #ece6dc;
  --bar: #00805f;
  --bar-track: rgba(0, 128, 95, 0.13);
}
@media (prefers-color-scheme: dark) {
  :root {
    --series-live: #0f9670; --series-msg: #ea6420;
    --grid: #2b2721; --bar: #0f9670; --bar-track: rgba(15, 150, 112, 0.20);
  }
}

.tiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
.tile { border: 1px solid var(--border); border-radius: 6px; background: var(--surface);
        padding: 14px 16px; display: flex; flex-direction: column; gap: 1px; }
.tile .label { font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.07em;
               text-transform: uppercase; color: var(--muted); }
.tile .value { font-size: 28px; font-weight: 650; letter-spacing: -0.03em;
               font-variant-numeric: tabular-nums; line-height: 1.15; }
.tile .note { font-size: 12.5px; color: var(--muted); }
.tile .note.risk { color: var(--risk); }
.tile .note.warn { color: var(--warn); }

/* A tile with a list behind it. Same box as the others, because it is the same
   number: the affordance is the cursor and the hover, not a different shape
   that would imply a different kind of figure. */
.tile-link { font: inherit; color: inherit; text-align: left; cursor: pointer; }
.tile-link:hover { border-color: var(--accent); background: var(--surface-2); }
.tile-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The star is the only control here that changes anything, so it stays quiet
   until it is either on or under the pointer. An always-orange column of empty
   stars would read as decoration and pull the eye off the titles. */
.star { font-size: 15px; line-height: 1; padding: 2px 4px; cursor: pointer;
        background: none; border: 0; border-radius: 4px; color: var(--muted); }
.star:hover { color: var(--accent); background: var(--surface-2); }
.star.on { color: var(--accent); }
.star:focus-visible { outline: 2px solid var(--accent); outline-offset: -1px; }
.star[disabled] { cursor: default; opacity: 0.45; }
/* Shrink the column to the star, the same way the copy column is shrunk to its
   button, so it does not steal width from the title. */
td:has(> .star) { width: 1%; padding-right: 4px; }

#write-error { margin: 0 0 12px; }

#deals-band { margin-bottom: 10px; }
.band { display: inline-flex; align-items: center; gap: 6px; font-family: var(--mono);
        font-size: 11px; padding: 2px 4px 2px 8px; border-radius: 4px;
        border: 1px solid var(--accent); color: var(--accent); background: var(--bg); }
.band-clear { font: inherit; line-height: 1; color: inherit; cursor: pointer;
              background: none; border: 0; border-radius: 3px; padding: 2px 4px; }
.band-clear:hover { background: var(--surface-2); }
.band-clear:focus-visible { outline: 2px solid var(--accent); outline-offset: -1px; }

.grid2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; margin-top: 16px; }
.card { border: 1px solid var(--border); border-radius: 6px; background: var(--surface);
        padding: 16px 18px 12px; position: relative; }
.card h3 { margin: 0 0 2px; font-size: 15px; font-weight: 600; letter-spacing: -0.012em; }
.card .cap { margin: 0 0 12px; font-size: 12.5px; color: var(--muted); max-width: 62ch; }
.card.wide { grid-column: 1 / -1; }
.chart-scroll { overflow-x: auto; }

.legend { display: flex; gap: 16px; flex-wrap: wrap; margin: 0 0 10px;
          font-size: 12.5px; color: var(--ink); }
.legend span { display: inline-flex; align-items: center; gap: 7px; }
.swatch { width: 11px; height: 11px; border-radius: 3px; flex: none; }
.swatch.live { background: var(--series-live); }
.swatch.msg { background: var(--series-msg); }

/* Recessive: the data is the only thing on the card that should be dark. */
.gridline { stroke: var(--grid); stroke-width: 1; }
.axis-text { font-family: var(--mono); font-size: 10.5px; fill: var(--muted); }
.bar-label { font-size: 12.5px; fill: var(--ink); }
.bar-value { font-family: var(--mono); font-size: 11.5px; fill: var(--muted); }
.hit { fill: transparent; cursor: pointer; }
.hit:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.table-toggle { position: absolute; top: 14px; right: 14px; background: none;
                border: 1px solid var(--border); border-radius: 5px; color: var(--muted);
                font: inherit; font-size: 12px; padding: 2px 9px; cursor: pointer; }
.table-toggle:hover { color: var(--ink); }
.table-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.data-table { width: 100%; border-collapse: collapse; margin-top: 8px; }
.data-table th, .data-table td { text-align: left; padding: 5px 10px 5px 0;
                                 border-bottom: 1px solid var(--border-soft); font-size: 13px; }
.data-table th { font-family: var(--mono); font-size: 10px; text-transform: uppercase;
                 letter-spacing: 0.07em; color: var(--muted); font-weight: 600; }
.data-table td.num { font-family: var(--mono); font-variant-numeric: tabular-nums; text-align: right; }

@media (max-width: 900px) {
  .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid2 { grid-template-columns: 1fr; }
}

/* Shown only on the new hostname, and only while the old one is still live.
   Somebody arriving here with a working Desk passkey will otherwise try it,
   fail with a browser-level error naming no cause, and conclude the app is
   broken rather than that they need to enrol once. */
#moved {
  max-width: 420px; margin: 24px auto 0; text-align: left;
  border: 1px solid var(--border); border-left: 2px solid var(--accent);
  border-radius: 6px; background: var(--surface);
  padding: 13px 16px; font-size: 13.5px; color: var(--muted);
}
#moved strong { display: block; color: var(--ink); font-size: 14px; margin-bottom: 3px; }
#moved em { color: var(--ink); font-style: normal; }

/* --------------------------------------------------------------- phone --- */
/*
 * One breakpoint, at 640px. That is every iPhone in portrait and no iPhone in
 * landscape, which is the split that matters: sideways there is room for the
 * tables, and forcing the card layout on 844px of width would waste it.
 *
 * The tables are the whole problem. Tickets is eight columns and Today is
 * seven, and no amount of narrowing fits those in 390px. The two usual answers
 * are both bad here: a horizontally scrolling table hides the columns that
 * carry the state behind a gesture nothing advertises, and a generic
 * label-value stack turns one ticket into eight lines and a screen into two
 * tickets. So each row becomes a card instead, with a deliberate three-line
 * shape: what it is and what you can do to it, then its title, then the
 * qualifiers, in that order because that is the order the eye needs them.
 *
 * Done in CSS against the existing markup rather than a second set of
 * renderers in app.js. One row builder, one place a column can be added.
 */

/* barsV is drawn at a fixed pixel width because its columns are a month each
   and squeezing them changes what the chart says. It still cannot be wider
   than the phone, so it scales as an image; barsH already uses width="100%". */
.card svg { max-width: 100%; height: auto; }

@media (max-width: 640px) {
  header { flex-wrap: wrap; gap: 10px 14px; padding-top: 10px; padding-bottom: 10px; }
  /* Name and who-you-are on the first line, tabs on their own line below.
     The tabs scroll sideways rather than wrapping to a third line, because
     five of them nearly fit and a lone "Today" on its own row looks broken. */
  nav { order: 3; width: 100%; overflow-x: auto; scrollbar-width: none;
        -webkit-overflow-scrolling: touch; padding-bottom: 2px; }
  nav::-webkit-scrollbar { display: none; }
  nav button { flex: none; padding: 6px 12px; }
  #who { margin-left: auto; }
  /* 16px exactly: iOS zooms the whole page in when a focused input is any
     smaller, and it does not zoom back out afterwards. */
  #search { order: 4; flex: 1 1 auto; min-width: 0; width: auto; margin-left: 0; font-size: 16px; }
  #search-count { order: 5; }

  main { padding-top: 14px; padding-left: max(14px, env(safe-area-inset-left));
         padding-right: max(14px, env(safe-area-inset-right)); }
  #login { padding: 48px 4px; }

  .tiles { gap: 8px; }
  .tile { padding: 11px 13px; }
  .tile .value { font-size: 23px; }
  .tile .note { font-size: 12px; }

  /* --- lists become cards --- */
  /* The table boxes are flattened to blocks rather than left as table-row-group
     wrapping flex rows. Browsers do cope with the hybrid, but it leaves
     anonymous table boxes in the tree that quietly ignore the row margin, and
     the gap between cards is the thing that makes them read as cards. */
  table { display: block; border: 0; background: none; border-radius: 0; overflow: visible; }
  tbody { display: block; }
  thead { display: none; }

  tbody tr {
    display: flex; flex-wrap: wrap; align-items: center; column-gap: 8px; row-gap: 5px;
    border: 1px solid var(--border); border-radius: 6px; background: var(--surface);
    padding: 11px 13px; margin-bottom: 8px;
  }
  tbody td { border: 0; padding: 0; font-size: 14px; }
  /* The "nothing here" row is a single cell and must not inherit any of the
     placement below, which is written for a full row. */
  tbody td[colspan] { flex-basis: 100%; font-size: 13.5px; }
  /* Undoes the desktop rules that shrink the star and copy columns to their
     buttons. `width: 1%` on a flex item is a basis, not a column hint, and
     would squash both of them to nothing. */
  td:has(> .copy), td:has(> .star) { width: auto; padding-left: 0; padding-right: 0; }

  /* Second line: the title, which is what you are actually reading for. */
  #tickets tbody td:nth-child(3),
  #today tbody td:nth-child(3),
  #deals tbody td:nth-child(2) { flex-basis: 100%; order: 5; font-size: 14.5px; line-height: 1.35; }

  /* Third line: the qualifiers, quiet and separated so they do not run together. */
  #tickets tbody td:nth-child(n + 5):nth-child(-n + 7),
  #today tbody td:nth-child(4), #today tbody td:nth-child(5),
  #deals tbody td:nth-child(3), #deals tbody td:nth-child(4) {
    font-size: 12.5px; color: var(--muted);
  }
  /* A separator only where something actually precedes it. The obvious version
     puts the dot on every qualifier but the first COLUMN, which is wrong the
     moment a column is empty: a ticket with no area but a company renders as
     "· STOKKE". These pair each cell with the ones that can sit before it, so
     the dot appears only when there is something on its left. */
  #tickets tbody td:nth-child(5):not(:empty) ~ td:nth-child(6):not(:empty)::before,
  #tickets tbody td:nth-child(5):not(:empty) ~ td:nth-child(7):not(:empty)::before,
  #tickets tbody td:nth-child(6):not(:empty) ~ td:nth-child(7):not(:empty)::before,
  #today tbody td:nth-child(4):not(:empty) ~ td:nth-child(5):not(:empty)::before,
  #deals tbody td:nth-child(3):not(:empty) ~ td:nth-child(4):not(:empty)::before {
    content: "·"; margin-right: 7px; color: var(--border);
  }

  /* Tickets: star, key, state, copy | title | area, company, assignee */
  #tickets tbody td:nth-child(1) { order: 1; }
  #tickets tbody td:nth-child(2) { order: 2; font-family: var(--mono); font-size: 12px;
                                   color: var(--muted); letter-spacing: 0.02em; }
  #tickets tbody td:nth-child(4) { order: 3; font-size: 12.5px; }
  #tickets tbody td:nth-child(8) { order: 4; margin-left: auto; }
  #tickets tbody td:nth-child(5) { order: 6; }
  #tickets tbody td:nth-child(6) { order: 7; }
  #tickets tbody td:nth-child(7) { order: 8; }

  /* Today: star, key, picked, copy | title | state, company */
  #today tbody td:nth-child(1) { order: 1; }
  #today tbody td:nth-child(2) { order: 2; font-family: var(--mono); font-size: 12px;
                                 color: var(--muted); letter-spacing: 0.02em; }
  #today tbody td:nth-child(6) { order: 3; }
  #today tbody td:nth-child(7) { order: 4; margin-left: auto; }
  #today tbody td:nth-child(4) { order: 6; }
  #today tbody td:nth-child(5) { order: 7; }

  /* Deals: company, state, copy | title | stage, next step. The company leads
     because it is the thing you recognise; on the desktop table the column
     header does that job and here there are no headers. */
  #deals tbody td:nth-child(1) { order: 1; flex: 1 1 auto; min-width: 0;
                                 font-weight: 600; letter-spacing: -0.008em; }
  #deals tbody td:nth-child(5) { order: 2; }
  #deals tbody td:nth-child(6) { order: 3; }
  #deals tbody td:nth-child(3) { order: 6; }
  #deals tbody td:nth-child(4) { order: 7; }

  /* --- recent --- */
  /* Flex rather than the desktop five-column grid, and two lines instead of
     one. The 760px rule above drops the chips and the state pill to make three
     columns fit; here there is room for them again on a second line, and they
     are worth having: the relationship chip and "due, 96d overdue" are most of
     why you would open the row. Name, state and recency stay on the first line
     with the chevron, so the row still reads as something that opens. */
  .row-head { display: flex; flex-wrap: wrap; align-items: center;
              gap: 5px 10px; padding: 10px 13px; }
  .row-head .co { order: 1; flex: 1 1 auto; min-width: 0; }
  .row-head .pill { display: inline-block; order: 2; flex: none; }
  .row-head .since { order: 3; flex: none; }
  .row-head .chev { order: 4; flex: none; }
  .row-head .chips { display: flex; order: 5; flex-basis: 100%; }
  .toolbar { gap: 10px; padding: 10px 13px; }
  .count-note { margin-left: 0; flex-basis: 100%; }
  .ev { grid-template-columns: 54px 14px minmax(0, 1fr); gap: 7px; font-size: 12.5px; }
  .tip { max-width: min(330px, calc(100vw - 32px)); }

  .group-head { padding-bottom: 6px; }
  .board { gap: 20px; }
}

/* Touch targets. The star and the copy button are both drawn small on purpose,
   and a 20px tap target is a miss waiting to happen. The padding grows and an
   equal negative margin takes it back out of the layout, so the row keeps its
   height and only the hit area changes. */
@media (pointer: coarse) {
  .star { padding: 11px; margin: -9px -7px; }
  .copy { padding: 11px; margin: -8px; }
  .band-clear { padding: 10px; margin: -8px; }
}
