/* evedeck design tokens - 00-common.md 5a.
   Nothing here is hand-set in a screen. If a value is needed that is not on
   this page, it is a decision, not a nudge. */

:root {
  /* Grey is the container, white is what sits inside or behind it.
     Sidebar and cards are grey; the header, the content ground and the
     nested stat boxes are white. */
  --white:    #FFFFFF;
  --panel:    #F4F6FA;
  --line:     #DEE3EC;
  --line-2:   #E8ECF3;
  --text:     #141821;
  --text-2:   #525A6B;
  --text-3:   #828B9C;
  --text-4:   #AEB6C4;
  --brand:    #1B5FBF;
  --brand-bg: #E6EEFB;

  /* Three steps, so hover and active read as different states. */
  --nav-hover:  #ECF0F7;
  --nav-active: #E0E7F2;

  /* Status colour never overlaps brand colour. Blue is identity;
     red, amber and green are signal. */
  --late:    #C0392B;  --late-bg: #FDEFEE;
  --soon:    #A8620B;  --soon-bg: #FCF3E6;
  --ok:      #0E7C4A;  --ok-bg:   #E8F4EE;

  /* Tints for a breakdown that carries no signal at all. Nobody's gender is a
     problem to be flagged, so it is never drawn in red, amber or green.
     founder 2026-08-27 */
  --tone-1:  #1B5FBF;
  --tone-2:  #7FA6DE;
  --tone-3:  #B9A0DC;

  --r:   4px;   /* containers - cards, panels, menus */
  --r-s: 3px;   /* controls - chips, buttons, stat boxes, nav rows */

  /* Sign-in only. The brand blue is a link colour; a whole panel of it is
     glare on a phone held in a lit shop. Same hue, two steps down. */
  --brand-deep: #123A72;

  --font: "IBM Plex Sans", -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-wordmark: "Outfit", var(--font);
}

* { box-sizing: border-box; }

/* 17px, 1.7 stroke, round caps and joins. Inline symbols, never a library:
   on a cheap Android on 3G an icon request is a visible delay.  00-common 5a */
.icon {
  width: 17px; height: 17px; flex: 0 0 auto;
  stroke: currentColor; fill: none;
  stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round;
  /* One rest colour for every icon, set here and nowhere else. A shade darker
     than the group labels: at --text-4 an icon reads as decoration, and the
     point of one is to be found at a glance. */
  color: var(--text-3);
}

body {
  margin: 0;
  font-family: var(--font);
  font-size: 14px;
  color: var(--text);
  background: var(--white);
  -webkit-font-smoothing: antialiased;
}

/* Every column of digits lines up or the list stops being scannable. */
.num, td.num, .big-number { font-variant-numeric: tabular-nums; }

a { color: var(--brand); text-decoration: none; }
a:hover { text-decoration: underline; }

.wordmark {
  font-family: var(--font-wordmark);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: .2em;
  margin-right: -.2em;
}

/* ------------------------------------------------------------ shell */

.shell { display: flex; min-height: 100vh; }

.sidebar {
  width: 208px;
  flex: 0 0 208px;
  background: var(--panel);
  border-right: 1px solid var(--line);
  padding: 14px 10px;
  display: flex; flex-direction: column;
}
.sidebar nav { flex: 1; }

.side-brand {
  display: flex; align-items: center; gap: 8px;
  padding: 2px 6px 16px;
  font-size: 16px; color: var(--text);
}

.nav-group {
  font-size: 9.5px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .12em; color: var(--text-4);
  padding: 14px 10px 6px;
}

/* One row per module. The icon carries the recognition, the word carries the
   meaning, and the row stays a single flat line either way.   00-common 6 */
.nav-link {
  display: flex; align-items: center; gap: 11px; position: relative;
  padding: 8px 10px; border-radius: var(--r-s);
  font-size: 13.5px; font-weight: 500; line-height: 1.2; color: var(--text-2);
}
.nav-link em { flex: 1; min-width: 0; font-style: normal;
               overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }


/* The number beside the word. Amber when it is a job rather than news — a
   figure he has to act on looks different from one he only reads. 00-common 5 */
.nav-count { font-size: 11px; font-weight: 600; color: var(--text-3);
             font-variant-numeric: tabular-nums; }
.nav-count.urgent { color: var(--soon); }

/* A module he does not have. Named so he knows it exists, marked so he is not
   surprised when it asks him to talk to us.   founder 2026-08-26 */
.nav-tag { font-size: 9px; font-weight: 600; text-transform: uppercase;
           letter-spacing: .06em; color: var(--text-4); }
.nav-link.active .nav-count { color: var(--text-2); }

.nav-link:hover        { background: var(--nav-hover); color: var(--text); text-decoration: none; }
.nav-link:hover .icon  { color: var(--text-2); }

/* Three steps of grey, then the icon turns brand colour and a bar appears at
   the edge. Hover and active have to read as different states. */
.nav-link.active       { background: var(--nav-active); color: var(--text); font-weight: 600; }
.nav-link.active .icon { color: var(--brand); }
.nav-link.active::before {
  content: ""; position: absolute; left: -10px; top: 7px; bottom: 7px;
  width: 3px; border-radius: 0 2px 2px 0; background: var(--brand);
}
.nav-link:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.header {
  height: 56px; display: flex; align-items: center; gap: 14px;
  padding: 0 18px; background: var(--white); border-bottom: 1px solid var(--line);
}

/* The screen's own icon, the same one as its sidebar row. Small: it names the
   screen, it does not announce it.   00-common 5a */
.page-chip {
  flex: 0 0 auto; width: 26px; height: 26px; border-radius: var(--r-s);
  background: var(--brand-bg); display: flex; align-items: center;
  justify-content: center;
}
.page-chip .icon { width: 15px; height: 15px; color: var(--brand); }

/* The name of the screen he is on. Without it every page looks the same at a
   glance and the sidebar is the only clue. */
.page-title { flex: 1; min-width: 0; margin: 0; font-size: 15px; font-weight: 600;
              white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Which business he is looking at. Always visible, because everything on the
   screen is scoped to it.   00-common 1a */
.shop-switch {
  display: flex; align-items: center; gap: 7px; margin: 0; flex: 0 0 auto;
  padding: 5px 10px; border: 1px solid var(--line); border-radius: var(--r-s);
  background: var(--panel); font-size: 13px; font-weight: 500; color: var(--text);
  max-width: 40vw; white-space: nowrap; overflow: hidden;
}
.shop-switch .icon { color: var(--brand); }
.shop-switch select {
  font: inherit; font-size: 13px; font-weight: 500; color: var(--text);
  border: 0; padding: 0; background: none; max-width: 30vw;
}

/* account -----------------------------------------------------------------

   A details element: the menu opens with no script at all, and the browser
   already closes it on Escape and on a click outside.                       */

.account { position: relative; flex: 0 0 auto; }
.account summary {
  display: flex; align-items: center; gap: 8px; padding: 5px 8px;
  border-radius: var(--r-s); cursor: pointer; list-style: none;
}
.account summary::marker { content: ""; }
.account summary:hover { background: var(--nav-hover); }
.account[open] summary { background: var(--nav-active); }

/* A person icon, not initials. Initials of a name nobody typed carefully read
   as a mistake, and two letters carry no information he did not already have -
   his own name is written beside it. */
.avatar {
  flex: 0 0 auto; width: 28px; height: 28px; border-radius: var(--r-s);
  background: var(--brand-bg); color: var(--brand);
  display: flex; align-items: center; justify-content: center;
}
.avatar .icon { width: 16px; height: 16px; color: var(--brand); }
.user-name { display: flex; flex-direction: column; line-height: 1.2; }
.user-name b { font-size: 12.5px; font-weight: 600; }
.user-name small { font-size: 10.5px; color: var(--text-3); }
.account .chev { width: 14px; height: 14px; color: var(--text-4); }

.account .menu {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 60;
  min-width: 210px; padding: 5px; background: var(--white);
  border: 1px solid var(--line); border-radius: var(--r);
  box-shadow: 0 8px 28px rgba(20, 24, 33, .12);
}
.menu-head { display: flex; align-items: center; gap: 9px; padding: 8px;
             border-bottom: 1px solid var(--line-2); margin-bottom: 4px; }
.menu-head b { display: block; font-size: 12.5px; }
.menu-head small { font-size: 11px; color: var(--text-3); }

.account .menu a {
  display: flex; align-items: center; gap: 9px; padding: 8px 9px;
  border-radius: var(--r-s); font-size: 13px; color: var(--text-2);
}
.account .menu a:hover { background: var(--nav-hover); color: var(--text); text-decoration: none; }
.account .menu a.danger { color: var(--late); }
.account .menu a.danger .icon { color: var(--late); }
.account .menu a.danger:hover { background: var(--late-bg); }

.content { padding: 20px; background: var(--white); flex: 1; }

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

.card-grid {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(196px, 1fr));
}

.card {
  display: block; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r); padding: 13px 14px 15px; color: inherit;
}
.card:hover { border-color: var(--text-4); text-decoration: none; }

/* The tinted icon chip. The strongest single element on the screen, and what
   makes it look finished rather than assembled.   00-common 5a */
.card-head { display: flex; align-items: center; gap: 9px; }
.chip {
  flex: 0 0 auto; width: 30px; height: 30px; border-radius: var(--r-s);
  display: flex; align-items: center; justify-content: center;
  background: var(--brand-bg); color: var(--brand);
}
/* The chip sets the colour and the icon has to take it. `.icon` names a colour
   on the svg itself, and a rule on the element beats one inherited from its
   parent - so every chip on the home screen and on the website tiles was
   drawing its icon in the default grey inside a blue box. It also carries the
   amber on a card that needs action, which was being lost the same way.
   founder 2026-08-26 */
.chip .icon { color: inherit; }
.card .label { flex: 1; font-size: 12.5px; font-weight: 500; color: var(--text-2); }
.card .arrow { width: 14px; height: 14px; color: var(--text-4); }
.card:hover .arrow { color: var(--text-2); }

.big-number { font-size: 26px; font-weight: 600; letter-spacing: -.028em; margin-top: 11px; }

/* A card that needs action looks different from one that informs. "8 due this
   week" is a job; "1,240 visits" is news.   00-common 5 */
.card.needs-action .chip { background: var(--soon-bg); color: var(--soon); }
.card.needs-action .big-number { color: var(--soon); }
.card.empty .big-number { color: var(--text-4); font-weight: 500; }

/* The last tile: a way to the rest, not a number. Dashed and unfilled so it
   reads as an opening in the grid rather than another card competing with
   the ones that carry real figures.   00-common 4, 5 */
.card.add {
  background: none; border-style: dashed; border-color: var(--line);
  display: flex; flex-direction: column; justify-content: space-between;
}
.card.add:hover { background: var(--panel); border-color: var(--text-4); }
.card.add .chip { background: var(--white); border: 1px solid var(--line-2); color: var(--text-3); }
.card.add:hover .chip { background: var(--brand-bg); color: var(--brand); border-color: transparent; }
.add-sub { margin-top: 11px; font-size: 12px; color: var(--text-4); }

/* The website screen's tiles. The same card as the home screen, because two
   grids that look different are two things to learn. A count shows as a
   number; everything else shows the thing itself, since "Forest" says more
   than "1 skin" ever could.   founder 2026-08-26                           */
.card .tile-text {
  margin-top: 11px; font-size: 15px; font-weight: 600; letter-spacing: -.012em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.card .tile-sub { margin-top: 5px; font-size: 12px; color: var(--text-4); line-height: 1.35;
                  white-space: normal; }

/* --------------------------------------------- a number, and what it is made of

   A figure that has to answer "made up of what" carries a legend or a row of
   bars, drawn in CSS and nothing else - no chart library, no canvas, no
   script, and it reads the same on a cheap Android as on a laptop.
   00-common 5a                                                              */

.legend { display: flex; flex-wrap: wrap; gap: 4px 14px; margin-top: 12px; }
.legend div { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-2); }
.legend i { width: 7px; height: 7px; border-radius: 2px; flex: 0 0 auto; }
.legend b { font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
/* Nothing recorded is drawn back, not drawn out. */
.legend .none { color: var(--text-4); }
.legend .none b { color: var(--text-3); }

/* Colour by what it means, never by where it sits in a list. */
.t-female  { background: var(--tone-1); }
.t-male    { background: var(--tone-2); }
.t-other   { background: var(--tone-3); }
.t-unknown { background: var(--line); }
/* An amount is recorded, or it is not. Neither is good or bad news, so it is
   brand colour and ground rather than green and red. */
.t-set     { background: var(--brand); }
.t-paid    { background: var(--ok); }
.t-part    { background: var(--soon); }
.t-unpaid  { background: var(--text-4); }
.t-present { background: var(--ok); }
.t-half    { background: var(--soon); }
.t-absent  { background: var(--late); }
.t-leave   { background: var(--brand); }

/* --------------------------------------------------------- a module dashboard

   A column per subject, and the figure and the detail behind it are one box.
   The version before this put the figures in a row and the detail in a second
   row underneath, and nothing said which panel belonged to which number - the
   founder read "Still to be paid" sitting under "Total employees" and could
   not tell it was about salary.

   Designed first in docs/mockups/employee-dashboard.html, direction C, chosen
   by the founder 2026-08-27. Design before code for any screen he has not
   already seen.   00-common 5b                                              */

/* As many columns as the module has subjects, not three because three is what
   the first one had. Founder, 2026-08-29: *"it is not mandatory to have 3
   cards in every dashboard. give as required. all dashboard need not be same.
   it should be easy and helpful."*   00-common 5b */
.dash-grid { display: grid; gap: 12px; grid-template-columns: repeat(3, 1fr); }
.dash-grid.two { grid-template-columns: repeat(2, 1fr); }
.dash-grid.one { grid-template-columns: minmax(0, 720px); }

.dash-col {
  position: relative; display: flex; flex-direction: column;
  background: var(--white); border: 1px solid var(--line); border-radius: var(--r);
}
/* The head is tinted and the body is white, so the figure and its detail read
   as one box with two parts rather than as two boxes. */
.dash-col-top {
  padding: 15px 17px 16px; background: var(--panel);
  border-bottom: 1px solid var(--line); border-radius: var(--r) var(--r) 0 0;
}
/* Room kept on the right for the button, which is lifted out of the flow so
   that on a phone it can drop to the foot of the card without the markup being
   written twice.   00-common 5a */
.dash-col-head { display: flex; align-items: center; gap: 10px; margin-bottom: 13px;
                 padding-right: 104px; }
.dash-col-head .chip { width: 32px; height: 32px; }
/* The heading names its subject - "Salary - August", never "Still to be paid".
   founder 2026-08-27 */
.dash-col-head h2 { flex: 1; min-width: 0; margin: 0; font-size: 13.5px; font-weight: 600;
                    color: var(--text-2); letter-spacing: -.006em;
                    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* The way in sits beside the heading, not at the foot of the column. It is the
   first thing he looks for and the columns are not the same height, so a link
   at the bottom of each one lands somewhere different every time.

   A small quiet button rather than a link: the head is tinted, and blue text on
   a grey band reads as part of the heading instead of as something to press.
   The same white-on-line control as button.quiet, one size down.
   founder 2026-08-27 */
.dash-col > .more {
  position: absolute; top: 15px; right: 17px;
  padding: 5px 10px; font-size: 12px; font-weight: 500;
  color: var(--text-2); background: var(--white);
  border: 1px solid var(--line); border-radius: var(--r-s);
  white-space: nowrap; text-decoration: none;
}
.dash-col > .more:hover {
  color: var(--text); border-color: var(--text-4); text-decoration: none;
}

.dash-figure { font-size: 33px; font-weight: 600; letter-spacing: -.03em; line-height: 1.02;
               font-variant-numeric: tabular-nums; }
.dash-figure small { font-size: 19px; font-weight: 500; color: var(--text-3);
                     letter-spacing: -.01em; }
.dash-key  { margin-top: 6px; font-size: 12.5px; font-weight: 500; color: var(--text-2); }
.dash-note { margin-top: 3px; font-size: 12px; color: var(--text-4); }

/* A figure that is a job looks different from one that informs. Salary is the
   only thing on this screen that is a job, so it is the only amber.
   00-common 5 */
.dash-col.needs-action .dash-figure,
.dash-col.needs-action .dash-key { color: var(--soon); }
.dash-col.needs-action .chip { background: var(--soon-bg); color: var(--soon); }
.dash-col.settled .dash-key { color: var(--ok); }
.dash-col.settled .chip { background: var(--ok-bg); color: var(--ok); }
/* Nothing to report is a real answer and reads as one. Never an em dash: that
   looks like the screen failed.   founder 2026-08-27 */
.dash-col.quiet .dash-figure { color: var(--text-4); }

.dash-col-body { flex: 1; padding: 10px 17px 14px; }

/* Label, bar, count. A breakdown reads as a measurement rather than as numbers
   he has to compare in his head. */
.bar-row {
  display: grid; grid-template-columns: 98px 1fr 32px; gap: 12px; align-items: center;
  padding: 7px 0; font-size: 13.5px;
}
.bar-track { height: 8px; background: var(--line-2); border-radius: 4px; overflow: hidden; }
.bar-fill { display: block; height: 100%; border-radius: 4px; }
.bar-row .n { text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; }
.bar-row.zero, .bar-row.zero .n { color: var(--text-4); }
/* The track is already the palest line on the page, so a fill drawn in it
   would be invisible. Inside a bar it is grey, not ground. */
.bar-fill.t-unknown { background: var(--text-4); }
/* A trade carries no meaning worth colouring, so every role bar is the same
   one. Colour is for what the colour says.   00-common 5a */
.bar-fill.t-role { background: var(--tone-2); }

/* A small label over a group of bars, where one column answers two questions.
   Each block carries its own rule, so the two never run together into one long
   list of numbers.   founder 2026-08-27 */
.block-head {
  margin: 13px 0 2px; padding-top: 13px; border-top: 1px solid var(--line-2);
  font-size: 12px; font-weight: 500; color: var(--text-2);
}
/* The first block sits straight under the figure, which already has the head's
   own border above it. */
.dash-col-body > .block-head:first-child { margin-top: 2px; padding-top: 0; border-top: 0; }
.bar-row .none { color: var(--text-4); }

.dash-empty { padding: 12px 0 18px; font-size: 13.5px; color: var(--text-3); }

/* Six months of what left his hand. Six divs and a height each - no chart
   library, no canvas, no script, and it draws before the fonts land.
   00-common 5a, 5b                                                          */
.spark-head { display: flex; align-items: baseline; justify-content: space-between;
              gap: 10px; font-size: 12px; font-weight: 500; color: var(--text-2); }
.spark-head .up-to { font-weight: 400; color: var(--text-4);
                     font-variant-numeric: tabular-nums; }
.spark { display: flex; align-items: flex-end; gap: 7px; height: 56px; margin-top: 10px; }
/* A fortnight is fourteen bars in the width six had, so they close up. */
.spark.days { gap: 3px; height: 46px; }
.spark-col { flex: 1; height: 100%; display: flex; align-items: flex-end; }
.spark-bar { display: block; width: 100%; min-height: 3px;
             border-radius: 2px 2px 0 0; background: var(--tone-2); }
/* The month in progress is hollow. Filled like the five behind it, a month
   three days old reads as a collapse in wages.   founder 2026-08-27 */
.spark-bar.now { background: var(--brand-bg); box-shadow: inset 0 0 0 1px var(--tone-2); }
.spark-x { display: flex; gap: 7px; margin-top: 6px; }
.spark-x span { flex: 1; text-align: center; font-size: 11px; color: var(--text-4); }
.spark-x span.now { color: var(--text-2); font-weight: 600; }

/* A fortnight, redrawn 2026-08-29. Founder, on the old one: "what is this?"
   Fourteen bars, no axis, and the days nobody had marked drawn as 3px stubs
   that read as "almost nobody came" - the opposite of "no record".   07-employees 16 */

/* Fourteen letters in the width six month names had, so they close up and the
   weekday is one character. Sunday is greyed: a shop shut on Sunday should be
   readable as a shut Sunday and not as a bad day.                          */
.spark-x.days { gap: 3px; }
.spark-x.days span { font-size: 10px; letter-spacing: 0; }
.spark-x.days span.rest { color: var(--text-5, var(--text-4)); opacity: .55; }

/* No record is a full-height empty box. Anything shorter is a claim about how
   many people came in, and the whole point is that nobody said.            */
.spark-bar.unmarked {
  height: 100%; background: transparent;
  box-shadow: inset 0 0 0 1px var(--line-2);
  border-radius: 2px;
}

/* The two ends of the window, and the one thing the drawing cannot say about
   itself. A swatch, not a sentence under the chart.                        */
.spark-ends { display: flex; align-items: center; justify-content: space-between;
              gap: 8px; margin-top: 7px; font-size: 11px; color: var(--text-4); }
.spark-ends .legend { display: inline-flex; align-items: center; gap: 5px; }
.spark-ends .swatch { width: 9px; height: 11px; border-radius: 2px;
                      box-shadow: inset 0 0 0 1px var(--line-2); }

/* Three columns is a wide-screen shape. Narrower, they stack in the order they
   were written - the team, today, then the money - and that order is the same
   at every width, so there is nothing to re-learn.   founder 2026-08-27 */
@media (max-width: 1000px) { .dash-grid { grid-template-columns: 1fr 1fr; } }

@media (max-width: 680px) {
  .dash-grid { grid-template-columns: 1fr; }

  /* A 29px button is not a thumb target. Apple asks for 44px and Android for
     48dp, so on a phone the button leaves the corner, drops to the foot of the
     card it belongs to, and takes the full width.   founder 2026-08-27 */
  .dash-col-head { padding-right: 0; }
  .dash-col > .more {
    position: static; display: block; width: 100%; min-height: 46px;
    padding: 13px 10px; font-size: 13.5px; text-align: center;
    color: var(--brand); background: var(--white);
    border: 0; border-top: 1px solid var(--line-2);
    border-radius: 0 0 var(--r) var(--r);
  }
  .dash-col > .more:hover { background: var(--panel); color: var(--brand); }
  .dash-col-body { padding-bottom: 4px; }
}

/* A heading with its own controls beside it - the month arrows belong to the
   salary list, not to the whole screen, now that the screen opens with figures
   that are not about one month.   founder 2026-08-27 */
.head-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap; margin: 24px 0 4px;
}
.head-row .section-head { margin: 0; }

/* ------------------------------------------------------------ forms */

.page-narrow { max-width: 340px; margin: 60px auto; padding: 0 20px; }

label { display: block; font-size: 12.5px; font-weight: 500; color: var(--text-2); margin: 14px 0 5px; }
/* Beside the label, not under the box: the number is there to be pressed and
   the box is there to be corrected.   founder 2026-08-27 */
a.ring { margin-left: 8px; font-size: 11.5px; font-weight: 600; letter-spacing: .04em;
         text-transform: uppercase; }

/* Every kind of box he types in, named by what it is not rather than by a
   list: `type=tel` was added for the phone field and fell straight out of a
   list of three, so the box lost its width, its padding and its border and
   nobody could see why.   founder 2026-08-27 */
input:not([type=checkbox]):not([type=radio]):not([type=file]):not([type=submit]):not([type=button]):not([type=hidden]),
select, textarea {
  width: 100%; padding: 8px 10px; font: inherit; font-size: 14px;
  border: 1px solid var(--line); border-radius: var(--r-s); background: var(--white);
}
input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--brand-bg); border-color: var(--brand);
}

/* Wrong as he types, not only when he presses the button. `:placeholder-shown`
   holds it back until there is something in the box, so an empty field is not
   red before he has touched it — which is why every field with a pattern also
   carries a placeholder. Pure CSS: the pattern does the deciding and no script
   is involved.   00-common 5a, founder 2026-08-27 */
input[pattern]:not(:placeholder-shown):invalid,
input[pattern]:not(:placeholder-shown):invalid:focus {
  border-color: var(--late); outline-color: var(--late-bg); background: var(--late-bg);
}

/* Flex, not inline-block. An svg on a text baseline sits low, so every button
   with an icon had the drawing and the word on different lines — and only the
   two places that set `inline-flex` for themselves looked right.
   founder 2026-08-27 */
button, .button {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  margin-top: 18px; padding: 9px 16px;
  font: inherit; font-size: 13.5px; font-weight: 500;
  color: #fff; background: var(--brand);
  border: 0; border-radius: var(--r-s); cursor: pointer;
}
/* The quiet control, wherever it is and whatever tag it is. It had a rule for
   `<button>` and two scoped ones for `.confirm-actions` and `.list-tools`, so
   every `<a class="button quiet">` outside those two — the month arrows, the
   panel headers, the head actions — rendered as a filled blue primary.
   founder 2026-08-27 */
button.quiet, .button.quiet, a[role=button].quiet {
  background: var(--white); color: var(--text-2); border: 1px solid var(--line);
}
button.quiet:hover, .button.quiet:hover, a[role=button].quiet:hover {
  background: var(--panel); color: var(--text); text-decoration: none;
}

/* An icon inside a button takes the button's own colour. `.icon` names a
   colour on the svg itself and a rule on the element beats one inherited from
   its parent, so every icon in a filled blue button was drawing in the default
   grey — the same fault as the chips, in a second place.
   00-common 5a, founder 2026-08-27 */
button .icon, .button .icon, a[role=button] .icon { color: inherit; }

/* A button with nowhere to go is turned off, not taken away. Removing it moves
   every button after it, so no two rows line up down the screen.
   founder 2026-08-26 */
/* pointer-events rather than a hover rule per place: every screen styles its
   own buttons on hover, and a turned-off one must not light up in any of
   them. */
button[disabled] { opacity: .3; cursor: default; pointer-events: none; }

.error { margin-top: 14px; padding: 9px 11px; border-radius: var(--r-s);
         background: var(--late-bg); color: var(--late); font-size: 13px; }
.notice { margin-top: 14px; padding: 9px 11px; border-radius: var(--r-s);
          background: var(--soon-bg); color: var(--soon); font-size: 13px; }

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

/* A real table: an outer rule, a headed top row, a line between every column
   and every row, and numbers that line up down the column. A list of two
   hundred businesses is read by scanning, and scanning needs edges. */

.table-scroll {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--white);
}

table { width: 100%; border-collapse: collapse; font-size: 13.5px; }

thead th {
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  text-align: left; vertical-align: bottom;
  font-size: 9.5px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .085em; color: var(--text-3);
  padding: 9px 12px; white-space: nowrap;
}

tbody td { padding: 10px 12px; border-top: 1px solid var(--line-2); vertical-align: middle; }
tbody tr:first-child td { border-top: 0; }
tbody tr:hover { background: #FAFBFD; }

/* One line between columns, from the header all the way down. */
th + th, td + td { border-left: 1px solid var(--line-2); }

/* Numbers, money and dates line up on the right or the column stops being
   scannable.   00-common 5a */
th.num, td.num { text-align: right; font-variant-numeric: tabular-nums; }

/* The serial number. It is a row's position in what is on screen, not an id,
   so it is quiet: narrow, muted, and it never competes with the name. */
th.sn, td.sn {
  width: 1%; text-align: right; white-space: nowrap;
  color: var(--text-3); font-variant-numeric: tabular-nums;
  padding-right: 10px;
}
td .sub { margin-top: 2px; }

/* A free-text column wraps inside a set width instead of stretching the table
   and pushing the columns after it off the screen. */
td.wrap-cell { max-width: 260px; white-space: normal; }

.tag { font-size: 9.5px; font-weight: 600; text-transform: uppercase; letter-spacing: .085em; }
.tag.draft  { color: var(--text-3); }
.tag.active { color: var(--ok); }
.tag.grace  { color: var(--soon); }
.tag.parked { color: var(--late); }

/* ------------------------------------------------------------ admin screens

   Everything below happens standing in a shop, not at a desk. The admin is
   built to the same constraint as the owner's app, which is easy to forget on
   a screen called admin.   10-admin 4                                       */

.page-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 14px; flex-wrap: wrap; margin-bottom: 18px;
}
.page-head h1 { font-size: 18px; font-weight: 600; margin: 0; }

/* The way back out of a part, on the screen rather than in the browser chrome.
   He arrived by tapping a tile, so the way back has to be where he is
   looking.   founder 2026-08-26                                            */
.back { display: inline-block; margin-bottom: 3px; font-size: 12.5px;
        color: var(--text-3); text-decoration: none; }
.back:hover { color: var(--text-1); text-decoration: none; }
.head-actions { display: flex; align-items: center; gap: 12px; }

/* His web address, and the way to look at it. A bordered pill rather than a
   link in grey text: the address is what he reads out across the counter and
   what he sends on WhatsApp, so it is shown rather than hidden behind the
   words "See it".   founder 2026-08-26                                      */
/* It is drawn in brand colour, not in grey. Grey text in a bordered box is
   what every screen in the world uses for a control that cannot be pressed, so
   the one link he most wants to press read as switched off.
   founder 2026-08-26 */
.site-pill {
  display: inline-flex; align-items: center; gap: 8px; max-width: 100%;
  padding: 7px 11px; border: 1px solid var(--line); border-radius: var(--r);
  background: var(--white); color: var(--brand); font-weight: 500;
  font-size: 12.5px; text-decoration: none;
}
.site-pill:hover {
  background: var(--brand-bg); border-color: var(--brand); color: var(--brand);
  text-decoration: none;
}
.site-pill .icon { width: 14px; height: 14px; flex: none; color: inherit; }
.site-pill .go { margin-left: auto; }
.site-address {
  font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* On a phone the header stacks, so the pill takes the width rather than
   sitting squeezed beside a title.                                          */
@media (max-width: 560px) {
  .page-head .head-actions { width: 100%; }
  .site-pill { width: 100%; }
}
.head-actions form { margin: 0; }
.head-actions button, .page-head .button { margin-top: 0; }

.quiet-link { font-size: 13px; color: var(--text-2); }

/* A footnote to something full width - a table, a list. It runs the full width
   too, because a short measure under a wide box reads as a broken layout, not
   as a considered line length. */
.note-under { margin-top: 14px; font-size: 12.5px; color: var(--text-3); }

/* Standing prose that is NOT under a wide box - an explanation above a narrow
   form. Here a measure is right, because nothing beside it sets the edge. */
.prose { max-width: 52ch; font-size: 12.5px; color: var(--text-3); }
.sub  { font-size: 12.5px; color: var(--text-3); }
.empty { font-size: 13.5px; color: var(--text-2); }
.section-head { font-size: 14.5px; font-weight: 600; margin: 22px 0 10px; }
.sub-head { font-size: 12.5px; font-weight: 600; color: var(--text-2); margin: 18px 0 6px; }

.ok-note {
  margin-bottom: 16px; padding: 9px 11px; border-radius: var(--r-s);
  background: var(--ok-bg); color: var(--ok); font-size: 13px;
}

textarea {
  width: 100%; padding: 8px 10px; font: inherit; font-size: 13.5px; line-height: 1.5;
  border: 1px solid var(--line); border-radius: var(--r-s); background: var(--white);
  resize: vertical;
}
select {
  width: 100%; padding: 8px 10px; font: inherit; font-size: 14px;
  border: 1px solid var(--line); border-radius: var(--r-s); background: var(--white);
}

/* list ------------------------------------------------------------------ */

.filters { display: flex; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; }
.filters input { flex: 1 1 220px; }
.filters select { flex: 0 0 150px; width: auto; }
.filters button { margin-top: 0; }

/* A table is the right shape for this list and the wrong shape for a phone,
   so it scrolls inside its own box rather than pushing the page sideways. */
.table-scroll table { min-width: 620px; }

/* new shop -------------------------------------------------------------- */

.one-field { max-width: 460px; }
.one-field button { margin-top: 12px; }

.cand-list { display: flex; flex-direction: column; gap: 8px; }
.cand {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 12px 14px; background: var(--panel);
  border: 1px solid var(--line); border-radius: var(--r);
}
.cand form { margin: 0; }
.cand button { margin-top: 0; }
.cand-name { font-size: 14px; font-weight: 600; }
.cand-meta { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 4px;
             font-size: 11.5px; color: var(--text-3); }
.flag { color: var(--soon); font-weight: 600; }

/* one shop -------------------------------------------------------------- */

.sections { display: grid; gap: 14px; grid-template-columns: 1fr; max-width: 760px; }

/* 760px is the width of a column of form fields, which is the right width for
   words and the wrong one for photographs. His photo screen takes everything
   the screen has, and the tiles grow with it - a row of fixed 96px strips in a
   wide column reads as a filmstrip rather than as his shopfront.
   founder 2026-08-26                                                        */
.sections.wide { max-width: none; }
/* A logo, a banner and a gallery, each in its own place. The banner used to be
   whichever photograph happened to be first, so reordering the gallery changed
   the top of his website by accident.   founder 2026-08-26                   */
.slots {
  display: grid; gap: 12px; margin: 14px 0 22px;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
}
.slot {
  display: flex; flex-direction: column; gap: 9px;
  padding: 12px; border: 1px solid var(--line); border-radius: var(--r);
  background: var(--panel);
}
.slot .shot { background: var(--white); }
/* One box, the same on both, whatever shape the file is. A preview that
   changes size when he swaps the picture makes the screen jump under his
   thumb.   founder 2026-08-26 */
.slot .shot { width: 100%; }
.slot .shot img { width: 100%; height: 104px; background: var(--white); }
/* A logo is judged whole, so it sits inside its box. A banner is judged as the
   wide strip it becomes, so it fills one. Neither is cropped on the way in and
   there is no crop tool.   09-public-extras 2 */
.slot-logo .shot img { object-fit: contain; }
.slot-banner .shot img,
.slot-gallery .shot img { object-fit: cover; object-position: center; }

/* The gallery is the same card as the two above it, across the full width.
   Three places for photographs that behave alike should look alike.
   founder 2026-08-26 */
.slot-gallery { margin-bottom: 4px; }
.slot-gallery .photo-grid { margin-top: 0; }
.slot form { margin: 0; }
.slot .button { margin-top: 0; }
/* Full width in the two single slots, where the button is the only thing on
   the row. The gallery's sits beside its count. */
.slots .slot .button { width: 100%; text-align: center; }

.slot-head { display: flex; flex-direction: column; gap: 2px; }
.slot-head b { font-size: 13px; font-weight: 600; }
.slot-head .sub { margin: 0; font-size: 11.5px; line-height: 1.4; }
/* The gallery's head is a row: the label on the left and the button hard right,
   where the eye ends up after reading the label rather than under it. It wraps
   on a phone rather than squeezing.   founder 2026-08-26 */
/* A heading with its control beside it. `display` was never set, so used on
   its own it stacked and the button dropped under the words — it only worked
   where `.slot-head` was on the same element.   founder 2026-08-27 */
.slot-head-row {
  display: flex; flex-direction: row; align-items: flex-start;
  justify-content: space-between; gap: 12px; flex-wrap: wrap;
  margin-bottom: 12px;
}
/* The words stack exactly as they do in the two slots above - name, then what
   it is, then the count. The row only puts the button beside them. */
.slot-head-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.slot-head-row form { flex: 0 0 auto; }
.slot-head-row .button, .slot-head-row a[role=button] { flex: 0 0 auto; margin-top: 0; }
.slot-head-row .slot-head-text .sub { margin-top: 2px; }

.slot-empty {
  display: flex; align-items: center; justify-content: center;
  height: 104px; border: 1px dashed var(--line);
  border-radius: var(--r); background: var(--white);
  font-size: 12px; color: var(--text-4);
}

/* Wider columns when the screen has the room. Every tile keeps the same
   height in all three places, on every width: one that changes height when he
   swaps the picture makes the page jump under his thumb.
   founder 2026-08-26 */
.sections.wide .photo-grid {
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}

.panel {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--r); padding: 16px;
}
.panel h2 { font-size: 14.5px; font-weight: 600; margin: 0 0 4px; }
.panel > form { margin-top: 6px; }

.pair { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 560px) { .pair { grid-template-columns: 1fr; } }

.checks { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 6px; }
.check {
  display: flex; align-items: center; gap: 9px; margin: 0;
  padding: 8px 10px; border-radius: var(--r-s); background: var(--white);
  border: 1px solid var(--line-2); font-size: 13.5px; font-weight: 400; color: var(--text);
}
.check input { margin: 0; accent-color: var(--brand); }
.from-plan {
  font-style: normal; font-size: 9.5px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .085em; color: var(--text-4); margin-left: auto;
}

.limits { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 10px; }
.limit { background: var(--white); border: 1px solid var(--line-2);
         border-radius: var(--r-s); padding: 9px 11px; }
.limit label { margin: 0 0 4px; font-size: 11.5px; }
.limit input { font-size: 13.5px; padding: 5px 8px; }
.limit .unit { font-size: 10px; color: var(--text-4); text-transform: uppercase;
               letter-spacing: .085em; }

.skins { display: flex; gap: 8px; flex-wrap: wrap; }
.skin-pick {
  display: flex; align-items: center; gap: 7px; margin: 0;
  padding: 7px 11px; border-radius: var(--r-s); background: var(--white);
  border: 1px solid var(--line-2); font-size: 12.5px; font-weight: 400; color: var(--text);
  cursor: pointer;
}
.skin-pick input { margin: 0; accent-color: var(--brand); }
.swatch { width: 13px; height: 13px; border-radius: 2px; display: inline-block; }

.plain { list-style: none; margin: 8px 0 0; padding: 0; font-size: 13.5px; }
.plain li { padding: 5px 0; border-top: 1px solid var(--line-2); }
.plain li:first-child { border-top: 0; }

.log { list-style: none; margin: 8px 0 0; padding: 0; font-size: 13px; }
.log li { display: flex; gap: 10px; align-items: baseline;
          padding: 6px 0; border-top: 1px solid var(--line-2); }
.log li:first-child { border-top: 0; }
.log-when { flex: 0 0 62px; color: var(--text-3); font-size: 11.5px; }
.log-what { flex: 1; }

/* ------------------------------------------------------------ on a phone

   The sidebar becomes a drawer. Same list, same order, nothing nested - it is
   the same navigation, not a reduced one.   00-common 6, 7                  */

.hamburger { display: none; align-items: center; background: none; border: 0;
             padding: 6px; margin: 0; color: var(--text-2); cursor: pointer; }
.scrim { display: none; }

@media (max-width: 760px) {
  .hamburger { display: inline-flex; }
  .sidebar {
    position: fixed; inset: 0 auto 0 0; z-index: 50; width: 250px;
    transform: translateX(-100%); transition: transform .18s ease;
    box-shadow: 0 0 40px rgba(20, 24, 33, .2);
  }
  body.nav-open .sidebar { transform: none; }
  body.nav-open .scrim {
    display: block; position: fixed; inset: 0; z-index: 40;
    background: rgba(20, 24, 33, .35);
  }
  .header { padding: 0 12px; gap: 8px; }
  /* The screen name and the person's name both go; which business he is on
     and the way out both stay, because those are the two he can be wrong
     about. */
  .page-title { display: none; }
  .page-chip { display: none; }
  .user-name { display: none; }
  .account .chev { display: none; }
  .shop-switch { flex: 1; max-width: none; }
  .content { padding: 16px 14px; }
  .card-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
}

/* A destructive action looks destructive, and only once you are next to it.
   The panel is quiet in the page and loud at the button.   10-admin 6 */
.panel.danger { border-color: var(--late); }
.panel.danger h2 { color: var(--late); }
/* The trigger that opens a delete question is a link, not a button, so this
   cannot be button-only or the most dangerous control on the screen would be
   the one that is not red.   founder 2026-08-26 */
.destructive { background: var(--late); color: #fff; }
.destructive:hover { background: #A32E22; color: #fff; text-decoration: none; }

/* One question before anything is deleted.   founder 2026-08-26

   The browser's own dialog element, styled to match. No library: a yes-or-no
   box is not worth 45 KB on a 3G phone, and everything here has to work with
   no script running at all. `:target` is what opens it without one - the
   trigger is a link to the dialog's id. The script upgrades that to a real
   modal and nothing more.   00-common 5a                                    */
.confirm {
  display: none;
  position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: min(370px, calc(100vw - 32px));
  margin: 0; padding: 20px 20px 18px;
  border: 1px solid var(--line); border-radius: var(--r);
  background: var(--white); color: var(--text);
  box-shadow: 0 18px 44px rgba(20, 24, 33, .18);
  z-index: 60;
}
.confirm[open], .confirm:target { display: block; }

/* The modal path gets the browser's backdrop; the script-free path paints its
   own, inside the dialog's own stacking context so it sits over the page and
   under the box.                                                            */
.confirm::backdrop { background: rgba(20, 24, 33, .45); }
.confirm:target::before {
  content: ""; position: fixed; inset: 0; z-index: -1;
  background: rgba(20, 24, 33, .45);
}

.confirm h2 { font-size: 15px; font-weight: 600; margin: 0 0 6px; }
.confirm p { font-size: 12.5px; line-height: 1.5; color: var(--text-2); margin: 0; }
/* One of the two is a link and the other is a button in a form, so nothing
   about their geometry can be left to the defaults: the link carries a border
   and a top margin the button does not, and two pixels is enough to see. Both
   are given the same box here and nowhere else.                              */
.confirm-actions {
  display: flex; align-items: stretch; justify-content: flex-end; gap: 10px;
  margin-top: 18px;
}
.confirm-actions form { display: flex; margin: 0; }
.confirm-actions .button,
.confirm-actions button {
  margin: 0; padding: 8px 16px;
  font-size: 13.5px; font-weight: 500; line-height: 1.25;
  border: 1px solid transparent; border-radius: var(--r-s);
  text-decoration: none;
}
.confirm-actions .button.quiet {
  background: var(--white); color: var(--text-2); border-color: var(--line);
}
.confirm-actions .button.quiet:hover { background: var(--panel); text-decoration: none; }

/* The same box, widened for a form and given a way out of its own. A man who
   opened it to look has to be able to leave without answering.   00-common 5a */
.sheet { width: min(620px, calc(100vw - 32px)); padding: 18px 20px 20px; }
.sheet-head { display: flex; align-items: flex-start; gap: 14px; margin-bottom: 4px; }
.sheet-head > div { flex: 1; min-width: 0; }
.sheet-close {
  flex: 0 0 auto; width: 28px; height: 28px; margin: -4px -4px 0 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 20px; line-height: 1; color: var(--text-3);
  border: 1px solid transparent; border-radius: var(--r-s); text-decoration: none;
}
.sheet-close:hover { color: var(--text); background: var(--panel);
                     border-color: var(--line); text-decoration: none; }
.sheet .pair { display: grid; gap: 0 14px; grid-template-columns: 1fr 1fr; }
.sheet label:first-of-type { margin-top: 10px; }
.sheet .sheet-do { display: flex; justify-content: flex-end; gap: 10px; margin-top: 18px; }
.sheet .sheet-do .button, .sheet .sheet-do button { margin-top: 0; }
@media (max-width: 560px) { .sheet .pair { grid-template-columns: 1fr; } }

/* people ------------------------------------------------------------------

   A month of staff, and a day of them. One row per person, read left to right:
   who, what they cost, what was marked, where it stands, what to do about it.
   07-employees 4, 06-attendance 3                                           */

.people { gap: 0; margin-top: 10px; }
.person {
  display: grid; gap: 4px 14px; align-items: center;
  padding: 14px 0; border-bottom: 1px solid var(--line-2);
  grid-template-columns: 1fr auto;
}
.person:last-child { border-bottom: 0; }
@media (min-width: 760px) {
  .person { grid-template-columns: 1.5fr .9fr 1.1fr auto auto; padding: 12px 0; }
  .person.mark { grid-template-columns: 1.4fr 1.1fr auto; }
}
.person-who { min-width: 0; display: block; color: inherit; }
.person-who b { display: block; font-size: 15px; font-weight: 600; }
.person-who .sub { margin: 0; }
a.person-who:hover b { color: var(--brand); }
.person-pay { display: flex; flex-direction: column; }
.person-pay .sub { margin: 0; }
.person-days { min-width: 0; }
.person-do form { margin: 0; }
.person-do button { margin-top: 0; padding: 7px 12px; font-size: 13px; }
/* Somebody who has left keeps his place in the months he was paid in.
   07-employees E-3 */
.person.gone { opacity: .62; }

/* Where the month stands. Amber is a job, green is news.   00-common 5 */
.tag-unpaid, .tag-part, .tag-paid {
  font-size: 10.5px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase;
  padding: 4px 8px; border-radius: var(--r-s); white-space: nowrap;
}
.tag-unpaid { background: var(--soon-bg); color: var(--soon); }
.tag-part   { background: var(--soon-bg); color: var(--soon); }
.tag-paid   { background: var(--ok-bg); color: var(--ok); }

/* One tap per person, four states, no save button.   06-attendance 3 */
.marks { display: flex; gap: 5px; flex-wrap: wrap; }
.marks form { margin: 0; }
.mark-btn {
  margin: 0; padding: 8px 12px; font-size: 12.5px; font-weight: 500;
  background: var(--white); color: var(--text-2);
  border: 1px solid var(--line); border-radius: var(--r-s);
}
.mark-btn:hover { background: var(--panel); color: var(--text); }
/* Present is the prominent one because most people come most days - but
   nothing is written until he taps it.   06-attendance 9 */
.mark-btn.lead { border-color: var(--line); color: var(--text); font-weight: 600; }
.mark-present.on { background: var(--ok-bg); color: var(--ok); border-color: var(--ok); }
.mark-absent.on  { background: var(--late-bg); color: var(--late); border-color: var(--late); }
.mark-half.on    { background: var(--soon-bg); color: var(--soon); border-color: var(--soon); }
.mark-leave.on   { background: var(--brand-bg); color: var(--brand); border-color: var(--brand); }

/* Moving between months and days. A step that leads nowhere is turned off
   rather than taken away, so the pair never shifts.   founder 2026-08-26 */
.months { gap: 6px; }
.months .button { margin-top: 0; padding: 8px 14px; }
.months .button.off { opacity: .3; pointer-events: none; }

.line-row { grid-template-columns: 1.4fr .8fr auto; align-items: baseline; }
.line-row .cell-name { font-size: 15px; }

/* The same figures the dashboard opens with, in one line above the list he is
   standing on. He asked for the collective detail here too, and a strip rather
   than three more cards: this screen's job is the list underneath it.
   founder 2026-08-27                                                        */
.stat-strip {
  display: flex; margin-bottom: 12px; overflow: hidden;
  border: 1px solid var(--line); border-radius: var(--r); background: var(--panel);
}
.stat-strip .cell { flex: 1; padding: 13px 17px; border-right: 1px solid var(--line); }
.stat-strip .cell:last-child { border-right: 0; }
.stat-strip .v { font-size: 24px; font-weight: 600; letter-spacing: -.025em;
                 line-height: 1.05; font-variant-numeric: tabular-nums; }
.stat-strip .k { margin-top: 4px; font-size: 12px; font-weight: 500; color: var(--text-2); }
.stat-strip .cell.none .v { color: var(--text-4); }
@media (max-width: 720px) {
  .stat-strip { flex-wrap: wrap; }
  .stat-strip .cell { flex: 1 1 50%; border-bottom: 1px solid var(--line); }
  .stat-strip .cell:nth-child(2n) { border-right: 0; }
}

/* The counts, spelled out beside their heading. Chips rather than the bars the
   dashboard draws: the same figures said twice in the same shape would read as
   the same screen twice, and this one's job is the list.   founder 2026-08-27 */
.count-rows { margin-bottom: 4px; }
.count-row { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
             padding: 7px 0; font-size: 13px; }
.count-row > .k { flex: 0 0 68px; font-size: 12px; font-weight: 500; color: var(--text-3); }
.count-chip {
  display: inline-flex; align-items: baseline; gap: 6px; padding: 4px 10px;
  font-size: 12.5px; color: var(--text-2);
  background: var(--white); border: 1px solid var(--line); border-radius: 20px;
}
.count-chip b { font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
.count-chip.zero { color: var(--text-4); background: none; }
.count-chip.zero b { color: var(--text-4); }
/* A chip he can press is a filter; the one that is on says so.
   founder 2026-08-27 */
a.count-chip { text-decoration: none; }
a.count-chip:hover { border-color: var(--text-4); color: var(--text); text-decoration: none; }
.count-chip.on, a.count-chip.on:hover {
  background: var(--brand); border-color: var(--brand); color: #fff;
}
.count-chip.on b { color: #fff; }

/* Search, and the way to take the whole list away with him. */
.list-tools { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
              margin-bottom: 12px; }
.list-tools form { display: flex; gap: 8px; margin: 0; flex: 1 1 260px; }
.list-tools input[type=search] {
  flex: 1; min-width: 0; padding: 8px 11px; font: inherit; font-size: 13.5px;
  border: 1px solid var(--line); border-radius: var(--r-s); background: var(--white);
}
.list-tools input:focus { outline: 2px solid var(--brand-bg); border-color: var(--brand); }
.list-tools button, .list-tools .button { margin-top: 0; padding: 8px 14px; font-size: 13px; }
.list-tools .button.quiet:hover .icon { color: var(--text); }
.showing { font-size: 12.5px; color: var(--text-3); }

/* a list of people -------------------------------------------------------

   A table with a header rather than a stack of rows: eight names with a role,
   a number and a salary each is a table, and pretending otherwise costs him
   the column headings that say which figure is which.
   Designed in docs/mockups/employee-screens.html, founder 2026-08-27        */

/* Eight columns will not fit a phone. The table scrolls sideways inside its
   own box rather than being cut off by it, and the box carries the border so
   the scroll never looks like a broken edge.   00-common 5a, founder 2026-08-27 */
.table-scroll { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--r);
                background: var(--white); }
.table-scroll .list-table { border: 0; border-radius: 0; min-width: 720px; }
.fold .table-scroll { border: 0; border-top: 1px solid var(--line-2); border-radius: 0; }
.fold .table-scroll .list-table { min-width: 420px; }

.list-table { border: 1px solid var(--line); border-radius: var(--r); overflow: hidden;
              background: var(--white); }
.list-head, .list-row { display: grid; align-items: stretch; }

/* Ruled both ways. With only horizontal lines he has to carry his eye across
   open space to work out which column a figure is in.   founder 2026-08-27 */
.list-head > span, .list-row > * { display: flex; align-items: center;
                                   padding: 11px 14px; min-width: 0; }
.list-head > span + span, .list-row > * + * { border-left: 1px solid var(--line-2); }

.list-head {
  background: var(--panel); border-bottom: 1px solid var(--line);
  font-size: 11px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase;
  color: var(--text-3);
}
.list-row { border-bottom: 1px solid var(--line-2); }
.list-row:last-child { border-bottom: 0; }
.list-row:hover { background: #FAFBFD; }
/* The serial and the chevron are markers, not readings. */
.list-head > span.no, .list-row > .no, .list-row > .go { justify-content: center; }

/* Two letters and a tint. evedeck holds no photograph of anybody who works in
   a shop, so this is the face.   00-common 11 */
.who-chip {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 12.5px; font-weight: 600; background: var(--brand-bg); color: var(--brand);
}
.who-chip.t2 { background: #F0E9F8; color: #7B54AE; }
.who-chip.t3 { background: var(--ok-bg); color: var(--ok); }
.who-chip.t4 { background: var(--soon-bg); color: var(--soon); }
.list-row.gone .who-chip { background: var(--line-2); color: var(--text-3); }

/* The face belongs with the name, in one cell. Two cells put a rule between a
   man and his own initials.   founder 2026-08-27 */
.list-row > .who { gap: 11px; color: inherit; text-decoration: none; }
.list-row .who .name { min-width: 0; }
.list-row .who b { display: block; font-size: 14.5px; font-weight: 600; letter-spacing: -.008em;
                   overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.list-row .who small { display: block; margin-top: 1px; font-size: 12px; color: var(--text-3);
                       overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
a.who:hover b { color: var(--brand); }
a.who:hover { text-decoration: none; }
.list-row .cell { font-size: 13px; color: var(--text-2);
                  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.list-row .cell.none { color: var(--text-4); }
/* One person's month, day by day. The day carries its weekday under it, so a
   run of blanks reads as Sundays rather than as neglect. */
.list-row .day small { margin-left: 7px; font-size: 12px; color: var(--text-4);
                       text-transform: uppercase; letter-spacing: .04em; }
.list-row.unmarked { background: #FCFDFE; }
.mark-tag {
  font-size: 11px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase;
  padding: 4px 9px; border-radius: var(--r-s); white-space: nowrap;
}
.mark-tag.mark-present { background: var(--ok-bg);   color: var(--ok); }
.mark-tag.mark-half    { background: var(--soon-bg); color: var(--soon); }
.mark-tag.mark-absent  { background: var(--late-bg); color: var(--late); }
.mark-tag.mark-leave   { background: var(--brand-bg);color: var(--brand); }
/* A column heading he can press to sort by it. */
.sortable { color: inherit; text-decoration: none; }
.sortable:hover { color: var(--text); text-decoration: none; }
.sortable.on { color: var(--brand); }
.sortable.on::after { content: " 93"; }

/* Picking a group, and what to do with them. */
.list-row > .pick, .list-head > span.pick { padding-left: 12px; padding-right: 6px; }
.list-row .pick input, .list-head .pick input {
  width: 16px; height: 16px; margin: 0; accent-color: var(--brand); cursor: pointer;
}
/* Not red. Red is signal - a problem, or something that cannot be undone -
   and taking somebody off the list is neither: nothing is deleted, he keeps
   every month he was paid in, and Reinstate is one tap away. It is the same
   quiet button as Download beside it.   00-common 5a, 07-employees E-3

   Nothing picked, nothing to remove. Turned off rather than taken away, so the
   row of controls never shifts.   founder 2026-08-26 */
.list-tools .button.pick-do:hover { border-color: var(--text-4); color: var(--text);
                                    text-decoration: none; }
.list-tools .button.pick-do.off { color: var(--text-4); pointer-events: none; opacity: .55; }
.list-foot { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-top: 12px; }
.list-foot .button, .list-foot > a[role=button] { margin-top: 0; }
.list-foot .sub { margin: 0; }
.pager { display: flex; align-items: center; gap: 10px; margin-left: auto; }
.pager .button { margin-top: 0; padding: 7px 13px; font-size: 13px; }
.pager .button.off { opacity: .3; pointer-events: none; }
.pager .sub { margin: 0; white-space: nowrap; }

/* Two men can share a name. Two rows that are one man entered twice look
   exactly like it, so this flags and never blocks.   founder 2026-08-27 */
.list-row .name small.warn {
  display: inline-block; margin-top: 2px; padding: 1px 6px;
  font-size: 10.5px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  background: var(--soon-bg); color: var(--soon); border-radius: 2px;
}

/* His own order, numbered. He asked for a serial rather than the up and down
   arrows: the numbers are what he reads them out by.   founder 2026-08-27 */
.list-row .no, .list-head .no { font-size: 12.5px; color: var(--text-4);
                                font-variant-numeric: tabular-nums; }
.list-row .moves { display: flex; gap: 4px; }
.list-row .moves form { margin: 0; }
.list-row .moves button { margin: 0; padding: 5px 9px; font-size: 12px; }
.list-row .go { color: var(--text-4); }
.list-row .go:hover { color: var(--brand); }
.list-row.gone { opacity: .72; }

/* Somebody who left is kept and is never in the way. A details element, so it
   opens with no script at all.   00-common 5a, 07-employees E-3 */
.fold { border: 1px solid var(--line); border-radius: var(--r); background: var(--white);
        margin-top: 12px; }
.fold > summary { padding: 12px 16px; font-size: 13.5px; font-weight: 500;
                  color: var(--text-2); cursor: pointer; list-style: none; }
.fold > summary::-webkit-details-marker { display: none; }
.fold > summary:hover { color: var(--text); }
.fold > summary .sub { display: inline; margin-left: 6px; color: var(--text-4); }
.fold .list-table { border: 0; border-top: 1px solid var(--line-2); border-radius: 0; }

/* A cake, on the day and never otherwise. Not a figure and not a job, so not
   a card: it sits beside the title and is gone tomorrow.
   founder 2026-08-27                                                        */
.cake {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 11px; border-radius: var(--r-s);
  background: var(--soon-bg); border: 1px solid transparent; text-decoration: none;
}
.cake .icon { width: 19px; height: 19px; color: var(--soon); }
.cake:hover { border-color: var(--soon); text-decoration: none; }
.cake .many { font-size: 13px; font-weight: 600; color: var(--soon);
              font-variant-numeric: tabular-nums; }
/* In the header it sits between the page title and the business, so it is
   compact and never pushes either off a narrow screen.   founder 2026-08-27 */
.header .cake { flex: 0 0 auto; margin-left: auto; padding: 6px 10px; }
.header .cake .many.today { font-size: 12px; letter-spacing: .02em; }
@media (max-width: 560px) { .header .cake .many { display: none; } }
/* The date, and how far off it is. Two facts in one cell, so the date leads
   and the distance follows it.   founder 2026-08-27 */
.list-row > .cell.when {
  flex-direction: column; align-items: flex-start; gap: 3px;
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.cell.when .line { display: flex; align-items: center; gap: 8px; }
.cell.when .wish { font-size: 12px; font-weight: 500; }
/* Every row is its own grid, so a column sized `auto` measures that row's own
   content and the columns drift apart between rows. Fixed widths or fractions
   only.   founder 2026-08-27 */
.list-row .cell.when small { font-size: 12px; color: var(--text-4); }

/* A panel he came to read, not to fill in. Label over value, and the form
   behind a button.   founder 2026-08-27                                     */
.facts { display: grid; gap: 12px 26px; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.facts > div { min-width: 0; }
.facts .k { display: block; font-size: 12px; font-weight: 500; color: var(--text-3); }
.facts .v { display: block; margin-top: 3px; font-size: 14.5px; }
.facts .v.big { font-size: 19px; font-weight: 600; letter-spacing: -.02em;
                font-variant-numeric: tabular-nums; }
.facts .v.none { font-size: 13.5px; color: var(--text-4); }
.facts .wish { display: inline-flex; align-items: center; gap: 5px; margin-top: 5px;
               font-size: 12.5px; font-weight: 500; }
.facts .wish .icon { width: 14px; height: 14px; color: var(--brand); }

/* what happened to somebody ----------------------------------------------

   "History" was six rows of past months with no heading. The word promises a
   record of what happened to a person and it delivered a payment list.
   07-employees 12, founder 2026-08-27                                       */

.timeline { position: relative; margin: 6px 0 2px; padding-left: 24px; }
.timeline::before {
  content: ""; position: absolute; left: 6px; top: 8px; bottom: 8px;
  width: 2px; background: var(--line);
}
.tl-item { position: relative; padding: 9px 0; }
.tl-item::before {
  content: ""; position: absolute; left: -22px; top: 15px;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--white); border: 2px solid var(--text-4);
}
/* Colour by what happened. A raise and a man leaving are not the same news. */
.tl-item.tl-salary::before, .tl-item.tl-role::before { border-color: var(--ok); }
.tl-item.tl-joined::before, .tl-item.tl-reinstated::before { border-color: var(--brand); }
.tl-item.tl-removed::before { border-color: var(--late); }
.tl-when { font-size: 12px; color: var(--text-4); }
.tl-what { margin-top: 1px; font-size: 13.5px; }

/* Three across, where a pair is two. The emergency contact is a name, a
   relationship and a number, and splitting it over two rows loses that they
   are one answer.   07-employees 12 */
.trio { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 0 14px; }
@media (max-width: 640px) { .trio { grid-template-columns: 1fr; } }

/* plans ------------------------------------------------------------------ */

.plan-head { display: flex; align-items: baseline; justify-content: space-between;
             gap: 12px; flex-wrap: wrap; margin-bottom: 2px; }
.plan-head h2 { margin: 0; }

.flags { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 14px; }
.flags .check { font-size: 13px; }

.plan-actions { margin-top: 4px; }
.plan-delete { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line-2); }
.plan-delete button { margin-top: 0; font-size: 12.5px; padding: 6px 11px; color: var(--late); }
.plan-delete button:hover { border-color: var(--late); }

/* A count and its unit read as one control, because they are one answer. */
.period { display: flex; gap: 6px; }
.period input { flex: 0 0 72px; }
.period select { flex: 1; }

/* photos -----------------------------------------------------------------

   A grid of what was just shot, big enough to tell one from another on a phone
   held at arm's length in a shop.   10-admin 4                              */

.photo-grid {
  display: grid; gap: 8px; margin-top: 14px;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
}

.shot { position: relative; margin: 0; border: 1px solid var(--line);
        border-radius: var(--r); overflow: hidden; background: var(--white); }
.shot img { width: 100%; height: 96px; object-fit: cover; display: block; }

/* Google's are the preview. Marked, so a live site is never left showing them. */
.shot.is-google { border-color: var(--soon); }
.shot.is-google::after {
  content: "Google"; position: absolute; top: 5px; right: 5px;
  font-size: 9px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  background: var(--soon-bg); color: var(--soon); padding: 2px 5px; border-radius: 2px;
}

.hero-tag {
  position: absolute; top: 5px; left: 5px;
  font-size: 9px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  background: var(--brand); color: #fff; padding: 2px 5px; border-radius: 2px;
}

.shot figcaption { display: flex; gap: 2px; padding: 4px; border-top: 1px solid var(--line-2); }
.shot figcaption form { margin: 0; flex: 1; }
/* The delete control is a link rather than a button, because it opens the
   question instead of doing the thing. It has to look identical to the three
   beside it.   founder 2026-08-26 */
.shot figcaption button, .shot figcaption a.drop {
  display: block; box-sizing: border-box; flex: 1; text-align: center;
  width: 100%; margin: 0; padding: 4px 0; font-size: 11px; font-weight: 500;
  background: var(--white); color: var(--text-2); border: 1px solid var(--line-2);
  border-radius: 2px; text-decoration: none; cursor: pointer;
}
.shot figcaption button:hover, .shot figcaption a.drop:hover {
  background: var(--panel); color: var(--text); text-decoration: none;
}
.shot figcaption button.drop:hover, .shot figcaption a.drop:hover {
  background: var(--late-bg); color: var(--late); border-color: var(--late);
}

/* A file input is unstyleable, so the label is the button and the input hides
   behind it. On a phone this opens the camera.   10-admin 4 */
label.button { margin-top: 0; color: #fff; cursor: pointer; }

/* tabs --------------------------------------------------------------------

   A business screen has nine sections and a plan has six. Stacked, that is a
   long scroll on a desk and a very long one on a phone held in a shop, where
   the founder wants one of them and knows which.   10-admin 4

   Every panel is rendered; the tab only decides which is shown. So a ?tab=
   link works with no script at all, and the script only saves the round trip.
*/

.tabs {
  display: flex; gap: 2px; overflow-x: auto; margin-bottom: 14px;
  border-bottom: 1px solid var(--line);
}
.tabs a {
  flex: 0 0 auto; padding: 9px 13px; border-radius: var(--r-s) var(--r-s) 0 0;
  font-size: 13px; font-weight: 500; color: var(--text-2);
  border: 1px solid transparent; border-bottom: 0;
  margin-bottom: -1px; white-space: nowrap;
}
.tabs a:hover { background: var(--nav-hover); color: var(--text); text-decoration: none; }

.tabs a.on {
  background: var(--white); color: var(--text); font-weight: 600;
  border-color: var(--line); border-bottom: 1px solid var(--white);
}
.tabs a .count {
  margin-left: 6px; font-size: 11px; font-weight: 600; color: var(--text-4);
  font-variant-numeric: tabular-nums;
}
.tabs a.on .count { color: var(--brand); }
.tabs a.warn .count, .tabs a.warn { color: var(--soon); }

.tab-panel[hidden] { display: none; }

/* editable rows -----------------------------------------------------------

   Four fields on one line, and on a phone they stack. Every row is its own
   form, so saving one never touches another and there is no Save All to
   forget.   01-website 5                                                    */

.rows-edit { display: flex; flex-direction: column; gap: 6px; margin: 12px 0; }

.row-edit {
  display: grid; gap: 6px; margin: 0; align-items: center;
  grid-template-columns: 1fr 1.6fr .9fr 1.2fr auto auto;
}
.row-edit input { font-size: 13.5px; padding: 6px 9px; }
.row-edit button { margin-top: 0; padding: 6px 10px; font-size: 12.5px; }
.row-edit .cell-price { font-variant-numeric: tabular-nums; }

.row-moves { display: flex; gap: 3px; align-items: stretch; }
.row-moves button { padding: 6px 8px; }
.row-moves a.drop {
  display: inline-flex; align-items: center; padding: 6px 10px;
  font-size: 12.5px; font-weight: 500; text-decoration: none;
  background: var(--white); color: var(--text-2);
  border: 1px solid var(--line); border-radius: var(--r-s);
}
.row-moves button.drop:hover, .row-moves a.drop:hover {
  background: var(--late-bg); color: var(--late); border-color: var(--late);
  text-decoration: none;
}

.row-add { padding-top: 10px; border-top: 1px solid var(--line-2); }

@media (max-width: 620px) {
  .row-edit { grid-template-columns: 1fr 1fr; }
  .row-edit .cell-name { grid-column: 1 / -1; }
  .row-moves { justify-content: flex-end; }
}

/* a module he has and does not use --------------------------------------- */

.start-module { max-width: 420px; margin: 40px auto; text-align: center; }
.start-module h2 { font-size: 17px; font-weight: 600; margin: 14px 0 6px; }
.start-module .prose { margin: 0 auto; text-align: center; font-size: 13.5px;
                       color: var(--text-2); }
.start-module button { margin-top: 18px; }
.start-module .sub { margin-top: 10px; }

.chip.big { width: 46px; height: 46px; margin: 0 auto; border-radius: var(--r); }
.chip.big .icon { width: 24px; height: 24px; }

/* Stop using it. A quiet line at the foot of the module, never a button
   competing with the work.   founder 2026-08-26 */
.module-foot { margin-top: 26px; padding-top: 14px; border-top: 1px solid var(--line-2); }
.module-foot button { margin: 0; padding: 0; background: none; border: 0;
                      color: var(--text-3); font-size: 12.5px; text-decoration: underline; }
.module-foot button:hover { color: var(--late); }

/* choose what you use -----------------------------------------------------

   Every module, a switch each, one Save. Rows big enough for a thumb, because
   this is done standing up on a phone.   00-common 7                        */

.chooser { max-width: 760px; }
.chooser-group { margin-bottom: 20px; }
.chooser-group h3 {
  font-size: 9.5px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .12em; color: var(--text-4); margin: 0 0 8px;
}

/* Two across on a desk, one on a phone. Twelve modules in a single column is
   a scroll for something he is meant to read at a glance.   00-common 7 */
.switches { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; }

@media (max-width: 620px) {
  .switches { grid-template-columns: 1fr; }
}

.switch-row {
  display: flex; align-items: center; gap: 11px; margin: 0;
  padding: 10px 12px; background: var(--panel);
  border: 1px solid var(--line); border-radius: var(--r);
  font-size: 14px; font-weight: 400; color: var(--text); cursor: pointer;
}
.switch-row:hover { border-color: var(--text-4); }
.switch-row.locked { cursor: default; opacity: .8; }
.switch-row.locked:hover { border-color: var(--line); }

.switch-text { flex: 1; display: flex; flex-direction: column; line-height: 1.3; }
.switch-text b { font-size: 13.5px; font-weight: 500; }
.switch-text small { font-size: 11.5px; color: var(--text-3); }

/* A real checkbox, scaled up: nothing to learn and nothing to script. */
.switch-row input[type=checkbox] {
  flex: 0 0 auto; width: 20px; height: 20px; margin: 0; accent-color: var(--brand);
}

.chooser button { margin-top: 4px; }

/* collapsed to a rail ------------------------------------------------------

   Eleven rows on a full plan, and a laptop carried into a shop is not a wide
   screen. Collapsed it is icons only, and the choice is remembered.

   A convenience: with the script blocked the sidebar simply stays open, which
   is the working state.   00-common 7                                       */

.rail-toggle {
  display: flex; align-items: center; gap: 11px; width: 100%;
  margin: 8px 0 0; padding: 8px 10px; border: 0; border-radius: var(--r-s);
  background: none; color: var(--text-3);
  font: inherit; font-size: 12.5px; font-weight: 500; cursor: pointer;
}
.rail-toggle:hover { background: var(--nav-hover); color: var(--text-2); }
.rail-toggle em { font-style: normal; }
.rail-toggle .icon { transform: rotate(180deg); transition: transform .15s ease; }

@media (min-width: 761px) {
  body.rail .sidebar { width: 58px; flex: 0 0 58px; padding: 14px 8px; }

  /* The words go; the icons and the marks that carry meaning stay. */
  body.rail .nav-link em,
  body.rail .rail-toggle em,
  body.rail .nav-tag,
  body.rail .wordmark { display: none; }

  body.rail .nav-link,
  body.rail .rail-toggle { justify-content: center; padding-left: 0; padding-right: 0; }
  body.rail .side-brand { justify-content: center; padding-left: 0; padding-right: 0; }
  body.rail .rail-toggle .icon { transform: none; }

  /* A count still shows, because it is the reason to look. */
  body.rail .nav-count {
    position: absolute; top: 3px; right: 6px; font-size: 9.5px;
  }
  body.rail .nav-group {
    padding: 12px 0 5px; text-align: center; font-size: 8px; letter-spacing: .06em;
    overflow: hidden; white-space: nowrap;
  }
  body.rail .nav-link.active::before { left: -8px; }
}

/* clients, vendors and contacts ------------------------------------------
   One module drawn three times, so everything here is shared. Only the words
   change between them.   12-parties 3                                      */

/* Two bars a month: what was raised, and what changed hands. A grouped bar
   rather than two charts, because the gap between the pair IS the answer. */
.spark-col.pair { gap: 2px; }
.spark-bar.billed  { background: var(--tone-3, #c7d2fe); }
.spark-bar.settled { background: var(--tone-2); }

/* Who is waiting for money, biggest first. A row, not a table: five names on a
   dashboard is a glance, and the list screen is one tap away. */
.owe-row { display: grid; grid-template-columns: 26px 1fr auto; align-items: center;
           gap: 9px; padding: 7px 0; text-decoration: none; color: inherit;
           border-top: 1px solid var(--line-2, var(--line)); }
.owe-row:first-of-type { border-top: 0; }
.owe-row:hover .owe-name { text-decoration: underline; }
.owe-row .who-chip { width: 26px; height: 26px; font-size: 10.5px; }
.owe-name { min-width: 0; font-size: 13.5px; font-weight: 500; line-height: 1.25;
            overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.owe-name small { display: block; font-size: 11.5px; font-weight: 400;
                  color: var(--text-4); }
.owe-amount { font-size: 13.5px; font-weight: 600; font-variant-numeric: tabular-nums;
              color: var(--warn-ink, var(--text-1)); }

/* A row on the money tab: what it was, what it came to, and where the balance
   stood after it. The running figure is the point of the table. */
.entry-amount.bill    { color: var(--text-1); }
.entry-amount.payment { color: var(--ok-ink, var(--text-1)); }
.entry-balance { font-variant-numeric: tabular-nums; color: var(--text-3); }

/* The row a panel's own Save sits on. The sheet has `.sheet-do`; a panel that
   is a form on the page had nothing, and the button sat flush against the last
   field.   founder 2026-08-28                                              */
.panel-do { display: flex; justify-content: flex-end; gap: 10px; margin-top: 16px; }
.panel-do button, .panel-do .button { margin-top: 0; }

/* the attendance register ------------------------------------------------
   People down the side, days across, one square a day. The register a shop
   already recognises, and the answer to "nothing to see".
   06-attendance 11, founder 2026-08-29                                     */

table.register { border-collapse: separate; border-spacing: 0; width: 100%;
                 font-size: 13px; background: var(--white); }
table.register th, table.register td { padding: 0; white-space: nowrap;
                                       border-bottom: 1px solid var(--line-2); }
table.register thead th {
  position: sticky; top: 0; z-index: 2; padding: 7px 0; text-align: center;
  background: var(--panel); border-bottom: 1px solid var(--line);
  font-size: 10.5px; font-weight: 600; color: var(--text-3);
}
table.register thead th small { display: block; font-size: 9.5px; font-weight: 500;
                                opacity: .7; }
/* The name column stays put while the days scroll past it. Without it the row
   he is reading loses the man it belongs to.   00-common 5a */
table.register th.who, table.register td.who {
  position: sticky; left: 0; z-index: 3; text-align: left; padding: 0 14px;
  min-width: 178px; background: var(--white);
  border-right: 1px solid var(--line-2);
}
table.register thead th.who { background: var(--panel); }
table.register td.who a { font-weight: 500; color: var(--text); text-decoration: none; }
table.register td.who a:hover { text-decoration: underline; }
table.register td.who small { display: block; font-size: 11.5px; color: var(--text-4); }
table.register td { height: 38px; text-align: center; }
table.register tbody tr:hover td { background: #FBFCFE; }

/* Sunday shaded, so a shop shut on Sunday reads as a shut Sunday and not as a
   week of absences.   06-attendance A-2 */
table.register th.rest, table.register td.rest { background: #FAFBFD; }
table.register th.now { color: var(--text-2); background: var(--brand-bg); }

table.register td.tot { padding: 0 14px; font-weight: 600; text-align: right;
                        font-variant-numeric: tabular-nums;
                        border-left: 1px solid var(--line-2); }
table.register td.tot small { font-weight: 400; color: var(--text-4); }
table.register th.tot { padding: 7px 14px; text-align: right;
                        border-left: 1px solid var(--line-2); }

table.register.wide td { padding: 0 12px; font-variant-numeric: tabular-nums; }
table.register.wide td a { color: var(--text); text-decoration: none; }
table.register.wide td a:hover { text-decoration: underline; }
table.register.wide td small { color: var(--text-4); margin-left: 2px; }
table.register.wide td.none { color: var(--text-4); }

.cellmark {
  display: inline-flex; width: 21px; height: 21px; border-radius: 3px;
  align-items: center; justify-content: center;
  font-size: 10px; font-weight: 700; color: var(--white); text-decoration: none;
}
.cellmark:hover { outline: 2px solid var(--brand); outline-offset: 1px; }
.cellmark.m-present { background: var(--ok); }
.cellmark.m-half    { background: var(--soon); }
.cellmark.m-absent  { background: var(--late); }
.cellmark.m-leave   { background: var(--brand); }
/* A day with no record is empty, never a colour. It is not an absence.  A-2 */
.cellmark.none { background: transparent; box-shadow: inset 0 0 0 1px var(--line-2); }

/* A mark made after the fact carries a dot. The record still settles the
   argument it exists for - it now says when it was written.   06-attendance O-1 */
.cellmark.late { position: relative; }
.cellmark.late::after {
  content: ""; position: absolute; top: 1.5px; right: 1.5px;
  width: 4px; height: 4px; border-radius: 50%;
  background: var(--white); box-shadow: 0 0 0 1px rgba(0,0,0,.18);
}

/* The legend sits above the table it explains — he reads down — so it needs
   room under it, not over it.   founder 2026-08-29 */
.mark-legend { display: flex; gap: 16px; flex-wrap: wrap;
               margin: 14px 0 12px; font-size: 12px; color: var(--text-3); }
.mark-legend span { display: inline-flex; align-items: center; gap: 6px; }
.mark-legend i { width: 12px; height: 12px; border-radius: 3px; display: inline-block;
                 position: relative; }
.mark-legend i.m-present { background: var(--ok); }
.mark-legend i.m-half    { background: var(--soon); }
.mark-legend i.m-absent  { background: var(--late); }
.mark-legend i.m-leave   { background: var(--brand); }
.mark-legend i.none { box-shadow: inset 0 0 0 1px var(--line-2); }
.mark-legend i.late::after { content: ""; position: absolute; top: 1px; right: 1px;
                             width: 4px; height: 4px; border-radius: 50%;
                             background: var(--white); }

/* A form sitting on a chip row — the two dates, or the three pickers.
   **One rule, and every control in it is the same height.** There were three:
   a date input came out at 38px from the base input rule, a select at 32 and a
   button at 30, so the two rows did not line up with each other or with the
   chips beside them.   founder 2026-08-29 */
.count-row form { display: inline-flex; align-items: center; gap: 7px;
                  flex-wrap: wrap; margin-left: 4px; }
/* The `:not` chain is copied from the base input rule above, because that rule
   is six `:not()`s deep — specificity (0,6,1) — and a plain `.count-row form
   input` at (0,1,1) never touched it. The date boxes stayed 100% wide and 38px
   tall, so the row broke into three lines and the Show button sat under them
   looking like a different button.   founder 2026-08-29 */
.count-row form input:not([type=checkbox]):not([type=radio]):not([type=file]):not([type=submit]):not([type=button]):not([type=hidden]),
.count-row form select,
.count-row form button,
.count-row form .button {
  flex: 0 0 auto; margin: 0; width: auto;
  height: 32px; padding: 0 11px; font-size: 12.5px; line-height: 1;
}
.count-row form input[type=date] { width: 152px; }
.count-row form input[type=search] { width: 200px; }

/* Show is filled light grey, so it reads as the thing that acts on the boxes
   beside it rather than as one more empty box on the row.   founder 2026-08-29 */
.count-row form button[type=submit] {
  background: var(--panel); border-color: var(--line); color: var(--text-2);
  font-weight: 600;
}
.count-row form button[type=submit]:hover { background: var(--line-2); color: var(--text); }
.count-row form select { padding-right: 26px; max-width: 210px; }
.count-row form .button { display: inline-flex; align-items: center; gap: 5px; }

/* The four buttons, against a person who has nothing marked yet, on the
   dashboard. The daily habit is done from the front page.   06-attendance 11 */
.dash-col-body .mark-row { display: grid; grid-template-columns: 1fr auto; gap: 10px;
                           align-items: center; padding: 8px 0;
                           border-top: 1px solid var(--line-2); }
.dash-col-body .mark-row:first-of-type { border-top: 0; }
.dash-col-body .mark-row .who { display: flex; align-items: center; gap: 9px;
                                min-width: 0; text-decoration: none; color: inherit; }
.dash-col-body .mark-row .who-chip { width: 26px; height: 26px; font-size: 10.5px; }
.dash-col-body .mark-row .name { min-width: 0; font-size: 13.5px; font-weight: 500;
                                 line-height: 1.2; overflow: hidden;
                                 text-overflow: ellipsis; white-space: nowrap; }
.dash-col-body .mark-row .name small { display: block; font-size: 11.5px;
                                       font-weight: 400; color: var(--text-4); }
.dash-col-body .mark-row .marks { display: flex; gap: 4px; }
.dash-col-body .mark-row .marks form { margin: 0; }
.mk { padding: 5px 9px; font-size: 12px; font-weight: 600; border-radius: var(--r-s);
      border: 1px solid var(--line); background: var(--white); color: var(--text-3); }
.mk:hover { border-color: var(--brand); color: var(--brand); }
.mk.go { border-color: var(--ok); color: var(--ok); }
.mk.go:hover { background: var(--ok); color: var(--white); }

/* A late entry, said beside the row it belongs to on the marking screen. */
.person .sub.late { color: var(--soon); }

/* One tap for the shop where everybody came, at the foot of the column that
   lists who is still unmarked.   06-attendance 11 */
.col-do { padding: 11px 17px 0; }
.col-do form { margin: 0; }
.col-do button { margin: 0; width: 100%; }

/* Four states, four columns, so every row wraps the same way. Ragged wrapping
   - two and two, then three and one - reads as a misprint on a phone.
   founder 2026-08-29 */
@media (max-width: 640px) {
  .person .marks { display: grid; grid-template-columns: repeat(4, 1fr); gap: 5px; }
  .person .marks .mark-btn { width: 100%; padding: 9px 2px; font-size: 11.5px;
                             white-space: nowrap; }
}

/* Four group buttons above the day's table. Twenty labourers all came in, or a
   whole shift did not, and marking them one at a time is twenty taps for one
   fact.   06-attendance 11a */
.group-do { display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
            margin: 0 0 10px; }
.group-do .k { font-size: 11.5px; font-weight: 600; letter-spacing: .055em;
               text-transform: uppercase; color: var(--text-3); margin-right: 3px; }
.group-do .mark-btn { margin: 0; }
/* Quiet until something is ticked. With the script blocked they stay live, so
   picking rows by hand still works.   00-common 5a */
.group-do .mark-btn.off { opacity: .45; }

/* The four buttons inside a row of the table. */
.list-row .marks { display: flex; gap: 4px; justify-content: flex-end;
                   flex-wrap: wrap; }
.list-row .marks .mark-btn { margin: 0; padding: 5px 9px; font-size: 11.5px;
                             font-weight: 600; }
/* `.list-row > *` is a flex row, so a `display: block` child of it is still a
   flex item sitting on the same line — the late note ran alongside the tag and
   was clipped by the column. The cell that carries both stacks them.
   founder 2026-08-29 */
.list-row > .cell.status { flex-direction: column; align-items: flex-start;
                           justify-content: center; gap: 3px; }
.list-row .cell small.late { font-size: 11px; line-height: 1.25; color: var(--soon);
                             white-space: normal; }

/* Today's mark, in the status column of the day table. The four states each
   have a colour everywhere else on the screen; a plain word here was the one
   place they did not.   06-attendance 11a */
.tag-present, .tag-half, .tag-absent, .tag-leave {
  display: inline-block; font-size: 10.5px; font-weight: 600; letter-spacing: .07em;
  text-transform: uppercase; padding: 4px 8px; border-radius: var(--r-s);
  white-space: nowrap;
}
.tag-present { background: var(--ok-bg);    color: var(--ok); }
.tag-half    { background: var(--soon-bg);  color: var(--soon); }
.tag-absent  { background: var(--late-bg);  color: var(--late); }
.tag-leave   { background: var(--brand-bg); color: var(--brand); }

/* Three pickers on the register, in one GET form. Chips a head was four rows
   of them before the table started. Sizing is the shared rule above.
   06-attendance 11c */

/* A day the shop was shut. It belongs to the shop and not to a person, so it
   is a line about the day and never a fifth button on every row.
   06-attendance 11d */
.shut-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
            padding: 10px 14px; margin-bottom: 12px; border-radius: var(--r);
            border: 1px solid var(--line-2); background: var(--white);
            font-size: 13.5px; }
.shut-row.on { background: var(--soon-bg); border-color: #F0DEC2; }
.shut-row form { display: inline-flex; align-items: center; gap: 7px; margin: 0; }
.shut-row form input:not([type=checkbox]):not([type=radio]):not([type=file]):not([type=submit]):not([type=button]):not([type=hidden]) {
  margin: 0; height: 32px; width: 190px; padding: 0 11px; font-size: 12.5px;
}
.shut-row form button { margin: 0; height: 32px; padding: 0 12px; font-size: 12.5px; }
.shut-row .sub { margin: 0; }
.tag-shut { font-size: 10.5px; font-weight: 600; letter-spacing: .07em;
            text-transform: uppercase; padding: 4px 8px; border-radius: var(--r-s);
            background: var(--soon); color: var(--white); white-space: nowrap; }

table.register th.shut, table.register td.shut { background: var(--soon-bg); }
table.register th.shut { color: var(--soon); }
.mark-legend i.shut { background: var(--soon-bg);
                      box-shadow: inset 0 0 0 1px #F0DEC2; }

/* Reasons a shop is shut, one tap each. They are submit buttons carrying their
   own value, not chips that fill a box: a chip that types into an input needs
   a script and nothing on an owner screen may.   00-common 5a */
.reason-chips { display: flex; flex-wrap: wrap; gap: 7px; margin: 2px 0 4px; }
.reason-chips button {
  margin: 0; height: 32px; padding: 0 13px; font-size: 12.5px; font-weight: 500;
  border-radius: 100px; border: 1px solid var(--line);
  background: var(--white); color: var(--text-2);
}
.reason-chips button:hover { border-color: var(--brand); color: var(--brand);
                             background: var(--brand-bg); }

/* A month of days inside a tab. Thirty-one rows would push everything under it
   off the screen, so the box scrolls and the panel keeps its shape. */
.table-scroll.tall { max-height: 420px; overflow-y: auto; }

/* A day the shop was shut, in the fortnight chart. It was drawn as an empty
   box — the same as a day he forgot — which is the one thing the holiday
   record exists to stop.   06-attendance 11d */
.spark-col.shut { background: var(--soon-bg); border-radius: 2px; }
.spark-bar.closed { height: 100%; background: transparent; border-radius: 2px;
                    box-shadow: inset 0 0 0 1px #E4C89A; }
.spark-ends .swatch.shut { background: var(--soon-bg);
                           box-shadow: inset 0 0 0 1px #E4C89A; }

/* The head-actions row carries a form now — a month box on salary, a year box
   on the year screen — so its controls take the same height as the buttons
   beside them.   founder 2026-08-29 */
.head-actions form.picks { display: inline-flex; align-items: center; gap: 7px;
                           margin: 0; }
.head-actions form.picks input:not([type=checkbox]):not([type=radio]):not([type=file]):not([type=submit]):not([type=button]):not([type=hidden]) {
  margin: 0; height: 34px; width: auto; padding: 0 10px; font-size: 12.5px;
}
.head-actions form.picks button { margin: 0; height: 34px; padding: 0 12px;
                                  font-size: 12.5px; background: var(--panel);
                                  border: 1px solid var(--line); color: var(--text-2);
                                  font-weight: 600; }
table.register tfoot td { background: var(--panel); font-weight: 600;
                          border-top: 1px solid var(--line); border-bottom: 0; }
table.register tfoot td.who { background: var(--panel); }

/* ------------------------------------------------------------ sign-in

   The only screens a person sees before they have signed in, and the only ones
   that have to sell rather than serve. Two columns on a laptop, one on a
   phone. Drawn first in docs/mockups/login.html.   00-common 5a, 5b        */

.auth { display: flex; min-height: 100vh; background: var(--white); }

/* The left half is the only place in the product that says what evedeck is.
   An owner reads it before he has bought anything and a staff member reads it
   on his first morning, so it is the panel and not a strip of colour. */
.auth-side {
  flex: 0 0 42%; max-width: 460px; padding: 38px 40px;
  display: flex; flex-direction: column; justify-content: space-between;
  color: #fff; background: var(--brand-deep);
  /* One wash of light, no photograph: an image is a request, and this screen
     loads on 3G before anything of ours is cached. */
  background-image: radial-gradient(120% 90% at 8% 0%, rgba(255,255,255,.14), transparent 55%);
}
.auth-side-top { display: flex; align-items: center; gap: 9px; font-size: 17px; }
.auth-side h2 { margin: 0 0 14px; font-size: 26px; line-height: 1.28;
                font-weight: 600; letter-spacing: -.015em; }
.auth-side p  { margin: 0 0 26px; font-size: 14px; line-height: 1.6;
                color: rgba(255,255,255,.72); }
.auth-points { list-style: none; margin: 0; padding: 0; }
.auth-points li { display: flex; gap: 11px; align-items: flex-start; margin: 11px 0;
                  font-size: 13.5px; line-height: 1.5; color: rgba(255,255,255,.9); }
.auth-points .icon { color: rgba(255,255,255,.62); margin-top: 1px; }
.auth-side-foot { font-size: 12px; color: rgba(255,255,255,.5); }

/* The phone version of the same panel: the mark and the name, nothing else.
   Three selling lines above the fold on a five-inch screen push the button
   below it, and the button is what he came for. */
.auth-strip {
  display: none; align-items: center; gap: 9px;
  padding: 20px 22px; color: #fff; background: var(--brand-deep); font-size: 16px;
}

.auth-main {
  flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: center;
  padding: 38px 40px calc(38px + env(safe-area-inset-bottom));
}
.auth-box { width: 100%; max-width: 352px; margin: 0 auto; }
.auth-box h1 { margin: 0; font-size: 22px; font-weight: 600; letter-spacing: -.01em; }
.auth-box .sub { margin: 7px 0 0; font-size: 13.5px; line-height: 1.55; color: var(--text-2); }

/* The two banners take an icon here, which the ones inside the app do not: a
   man who has just been refused entry is reading faster than he reads any
   screen after it. */
.auth .error, .auth .notice { display: flex; gap: 9px; align-items: flex-start;
                              line-height: 1.45; }
.auth .error .icon { color: var(--late); margin-top: 1px; }
.auth .notice .icon { color: var(--soon); margin-top: 1px; }
/* Signed out is not a warning. Amber for it tells him something went wrong on
   the way out, which is the opposite of what happened. */
.auth .notice.good { background: var(--ok-bg); color: var(--ok); }
.auth .notice.good .icon { color: var(--ok); }

/* 16px, not the 14px every other box on the site uses. Below 16px Safari on an
   iPhone zooms the page the moment the box is focused, and he is left
   scrolling sideways to find the button he was about to press. */
.auth input:not([type=checkbox]):not([type=radio]):not([type=file]):not([type=submit]):not([type=button]):not([type=hidden]),
.auth select {
  height: 46px; padding: 0 12px; font-size: 16px;
}
/* The form is a block under the sentence that introduces it, not the next
   line of it. Without this the first label sits tight against the sub. */
.auth form { margin-top: 22px; }
.auth label { margin: 16px 0 6px; }
.auth form > label:first-child { margin-top: 0; }

.with-eye { position: relative; }
.with-eye input { padding-right: 46px; }
/* 44px square. A control smaller than a fingertip, on the one screen a man
   uses before he trusts the product, is the wrong place to save space. */
.eye {
  position: absolute; right: 1px; top: 1px; width: 44px; height: 44px;
  margin: 0; padding: 0; border: 0; background: none; border-radius: var(--r-s);
  display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.eye:hover { background: var(--panel); }
.eye .icon { color: var(--text-3); }

/* Full width, and taller than a button inside the app. It is the only thing on
   the screen to press. */
.auth .go {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  width: 100%; height: 46px; margin-top: 22px; padding: 0;
  font-size: 14.5px; font-weight: 500;
}
.auth .go:hover { background: #17539F; text-decoration: none; }
.auth .go:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

/* Google's own button, to their guidelines: white ground, their mark at 18px,
   their wording. A blue button with a G in it is the thing people have been
   taught to distrust. */
.auth .go-google { background: var(--white); color: var(--text); border: 1px solid #CDD3DE; }
.auth .go-google:hover { background: var(--panel); border-color: var(--text-4); }

.auth-foot { margin-top: 26px; padding-top: 18px; border-top: 1px solid var(--line-2);
             font-size: 12.5px; line-height: 1.6; color: var(--text-3); }
.auth-help { margin-top: 10px; font-size: 12.5px; color: var(--text-3); }

/* 820px, not the 760px the shell uses: this layout is two columns of text and
   it crowds sooner than a sidebar beside a table does. */
@media (max-width: 820px) {
  .auth { flex-direction: column; }
  .auth-side { display: none; }
  .auth-strip { display: flex; }
  .auth-main { padding: 30px 22px calc(34px + env(safe-area-inset-bottom));
               justify-content: flex-start; }
}

/* The line between the two ways in. Google above it, the password below.
   Without it the Google button reads as the label on the form under it.
   migration 026 */
.auth .or {
  display: flex; align-items: center; gap: 12px; margin: 22px 0 0;
  font-size: 11.5px; font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase; color: var(--text-4);
}
.auth .or::before, .auth .or::after {
  content: ""; flex: 1; height: 1px; background: var(--line);
}
