/* ---------------------------------------------------------------------------
   The vocabulary's looks. Pairs with app/ui.js: if it is not a component there,
   it has no styles here.

   The scales are the point. Every spacing and every size in the panel comes
   from these, so two things that should look alike cannot drift apart because
   they were written a month apart — which is exactly how the previous version
   ended up with five kinds of row and four kinds of button.
   --------------------------------------------------------------------------- */

:root {
  /* Spacing. Six steps, and nothing between them. */
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 18px;
  --s5: 28px;
  --s6: 44px;

  /* Type. Five sizes, and the figures that have to be compared use --mono. */
  --t-micro: 11.5px;
  --t-small: 13px;
  --t-body:  15px;
  --t-lead:  19px;
  --t-title: 26px;
  --t-figure: 34px;
}

/* --- the container -------------------------------------------------------- *

   There isn't one, and that is the change. Everything used to be a bordered box: six
   identical dark rectangles down a page, which is the most worn pattern in dashboard design
   and reads as a template rather than a product. Boxes are also a crutch — they separate
   things so the typography doesn't have to.

   So a section is a heading and its content, separated by space. A surface appears only where
   something genuinely is an object you could point at: the person, their handset. Those two
   are the parts that were working.
   --------------------------------------------------------------------------- */

.card { padding: 0; background: none; border: 0; animation: rise .34s cubic-bezier(.2,.7,.3,1) both; }
.card + .card { margin-top: var(--s6); }

/* Sections arrive rather than appear. Once, on paint, never on hover. */
@keyframes rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .card, .person, .handset { animation: none; }
}

.card-head {
  display: flex; align-items: center; gap: var(--s3);
  margin-bottom: var(--s4);
  padding-bottom: var(--s3);
  /* One hairline under the heading instead of four around everything. It says "this is where
     the section starts" and takes up no room saying it. */
  border-bottom: 1px solid var(--line-soft);
}
.card-title { min-width: 0; flex: 1; }
.card-head h2 {
  margin: 0;
  font-size: var(--t-title); font-weight: 700; letter-spacing: -.032em;
  text-wrap: balance;
}
.card-head .hint {
  margin: var(--s2) 0 0; color: var(--ink-2); font-size: var(--t-body);
  max-width: 62ch; text-wrap: pretty;
}
.card-actions { display: flex; align-items: center; gap: var(--s3); flex-shrink: 0; }

/* --- facts ---------------------------------------------------------------- */

.facts { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 0; margin: 0; }
.facts dt,
.facts dd {
  margin: 0;
  padding: var(--s3) 0;
  border-top: 1px solid var(--line-soft);
}
.facts dt:first-of-type, .facts dt:first-of-type + dd { border-top: 0; }
.facts dt { color: var(--ink-2); font-size: var(--t-body); }
.facts dt small { display: block; color: var(--ink-3); font-size: var(--t-micro); }
.facts dd { text-align: right; font-variant-numeric: tabular-nums; }

/* --- figures -------------------------------------------------------------- */

.stats { display: flex; flex-wrap: wrap; gap: var(--s5); }
.stat { display: flex; flex-direction: column; gap: var(--s1); min-width: 88px; }
.stat-name { font-size: var(--t-small); color: var(--ink-2); font-weight: 550; }
.stat-value {
  font-size: var(--t-figure); font-weight: 600; line-height: 1;
  letter-spacing: -.03em; font-variant-numeric: tabular-nums;
}
.stat-unit { font-size: var(--t-lead); font-weight: 500; color: var(--ink-2); margin-left: 2px; }
.stat-note { font-size: var(--t-small); color: var(--ink-2); }
.stat.ok .stat-value { color: var(--ok); }
.stat.warn .stat-value { color: var(--warn); }
.stat.bad .stat-value { color: var(--bad); }

/* --- controls ------------------------------------------------------------- */

.field {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s5);
  padding: var(--s4) 0;
  border-top: 1px solid var(--line-soft);
}
.field:first-child { border-top: 0; padding-top: 0; }
.field:last-child { padding-bottom: 0; }
.field-label { min-width: 0; }
.field-label span { font-size: var(--t-lead); font-weight: 550; letter-spacing: -.01em; }
.field-label small {
  display: block; margin-top: var(--s1);
  color: var(--ink-2); font-size: var(--t-small); max-width: 56ch; text-wrap: pretty;
}
.field-control { flex-shrink: 0; }

/* Free text gets the width of the page. An address in a 220px box beside its own label reads
   as "Calle Mayor 14, 3º B28013 M" — cut off mid-word, which is how a form says it was never
   filled in by the person who designed it. */
.field.stacked { flex-direction: column; align-items: stretch; gap: var(--s3); }
.field.stacked .field-control { width: 100%; }
.field.stacked .text-input { width: 100%; min-width: 0; }

.choice,
.number input {
  font: inherit; font-size: var(--t-body);
  padding: var(--s2) var(--s3);
  color: var(--ink); background: var(--ground);
  border: 1px solid var(--line); border-radius: var(--r);
}
.text-input {
  font: inherit; font-size: var(--t-body);
  padding: var(--s2) var(--s3); min-width: 220px;
  color: var(--ink); background: var(--ground);
  border: 1px solid var(--line); border-radius: var(--r);
}
.text-input:focus,
.choice:focus,
.number input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-wash); }

.number { display: flex; align-items: baseline; gap: var(--s2); }
.number input { width: 88px; text-align: right; font-variant-numeric: tabular-nums; }
.number .unit { color: var(--ink-3); font-size: var(--t-small); }

.slider { display: flex; align-items: center; gap: var(--s3); }
.slider input { width: 190px; accent-color: var(--accent); height: 22px; }
.slider output {
  min-width: 68px; text-align: right;
  font-size: var(--t-body); font-weight: 600; color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.toggle { display: inline-flex; align-items: center; gap: var(--s2); cursor: pointer; }
.toggle-word { font-size: var(--t-micro); color: var(--ink-3); }
.toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
.toggle .track {
  width: 42px; height: 24px; padding: 2px;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 999px;
  transition: background .14s ease, border-color .14s ease;
}
.toggle .knob {
  display: block; width: 18px; height: 18px; border-radius: 50%;
  background: var(--ink-3); transition: transform .14s ease, background .14s ease;
}
.toggle input:checked + .track { background: var(--accent-wash); border-color: var(--accent-deep); }
.toggle input:checked + .track .knob { transform: translateX(18px); background: var(--accent); }
.toggle input:focus-visible + .track { outline: 2px solid var(--accent); outline-offset: 2px; }

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

.actions { display: flex; flex-wrap: wrap; gap: var(--s2); }

.button {
  font: inherit; font-size: var(--t-body); font-weight: 600;
  padding: var(--s3) var(--s5); border-radius: 999px;
  border: 1px solid var(--line); background: transparent; color: var(--ink);
  cursor: pointer;
  transition: transform .12s ease, border-color .12s ease, background .12s ease, box-shadow .12s ease;
}
/* Only the plain one changes its ground on hover. This used to apply to every button, and
   `.button:hover` is more specific than `.button.primary`, so pointing at the amber button
   replaced its fill with dark surface while the text stayed near-black: a button nobody could
   read, at the exact moment they were about to press it. */
.button.plain:hover:not(:disabled),
.button:not(.primary):not(.danger):hover:not(:disabled) {
  border-color: var(--ink-3); background: var(--surface-2);
}
.button:hover:not(:disabled) { transform: translateY(-1px); }
.button:active:not(:disabled) { transform: none; }
.button:disabled { opacity: .4; cursor: default; }

/* The one that does the thing somebody came for. It looks like a lit button because it is. */
.button.primary {
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 92%, white) 0%, var(--accent) 100%);
  border-color: color-mix(in srgb, var(--accent) 60%, black);
  color: var(--accent-ink);
  box-shadow: 0 6px 18px color-mix(in srgb, var(--accent) 28%, transparent);
}
.button.primary:hover:not(:disabled) {
  box-shadow: 0 10px 24px color-mix(in srgb, var(--accent) 36%, transparent);
}
.button.danger { border-color: color-mix(in srgb, var(--bad) 45%, transparent); color: var(--bad); }
.button.danger:hover:not(:disabled) { background: var(--bad-wash); border-color: var(--bad); }
.button:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.icon-button {
  width: 30px; height: 30px; padding: 0;
  display: inline-grid; place-items: center;
  font: inherit; font-size: var(--t-small);
  color: var(--ink-2); background: transparent;
  border: 1px solid transparent; border-radius: var(--r);
  cursor: pointer;
}
.icon-button:hover { color: var(--ink); background: var(--surface-2); border-color: var(--line); }

/* --- the rest ------------------------------------------------------------- */

/* A short verdict, and it has to sit level with whatever is beside it. It used to be
   baseline-aligned against a button, which left the pill low and crushed into its neighbour. */
.badge {
  display: inline-flex; align-items: center; white-space: nowrap;
  padding: var(--s1) var(--s3); border-radius: 999px;
  font-size: var(--t-small); font-weight: 600; letter-spacing: 0;
  text-transform: none;
  background: var(--surface-2); color: var(--ink-2);
}
.badge.ok   { background: var(--ok-wash);   color: var(--ok); }
.badge.warn { background: var(--warn-wash); color: var(--warn); }
.badge.bad  { background: var(--bad-wash);  color: var(--bad); }

/* A rule inside a card, where one card holds two kinds of thing: the figures somebody reads
   at a glance and the facts behind them. Not a second card, because it is one answer. */
.card-split { margin-top: var(--s5); padding-top: var(--s4); border-top: 1px solid var(--line-soft); }

/* Cards down a page, one gap between them and no other spacing anywhere. */
.stack { display: flex; flex-direction: column; gap: var(--s3); }

/* ---------------------------------------------------------------------------
   The daily surface. The person, their screen, what has happened.

   The shapes here are not shared with anything else on purpose: this is the one
   page somebody opens because they are worried, and it is allowed to look
   unlike a settings form.
   --------------------------------------------------------------------------- */

.today { display: flex; flex-direction: column; gap: var(--s5); }

/* --- the person ----------------------------------------------------------- */

.person {
  display: flex; align-items: center; gap: var(--s4);
  padding: var(--s5); 
  border-radius: var(--r-lg);
  box-shadow: 0 12px 34px rgba(0,0,0,.3);
  animation: rise .4s cubic-bezier(.2,.7,.3,1) both;
  /* A wash rather than a border: the verdict colours the ground the face sits on, which is
     how a glance reads it before a single word is parsed. */
  background: linear-gradient(160deg, var(--wash) 0%, transparent 78%);
  --wash: var(--surface-2);
}
.person.ok   { --wash: var(--ok-wash); }
.person.warn { --wash: var(--warn-wash); }
.person.bad  { --wash: var(--bad-wash); }

.face {
  width: 92px; height: 92px; flex-shrink: 0;
  border-radius: 50%; object-fit: cover;
  border: 2px solid var(--line);
  background: var(--surface-2);
}
.face.no-photo {
  display: grid; place-items: center;
  font-size: var(--t-title); font-weight: 650; color: var(--ink-3);
  letter-spacing: -.02em;
}

.person-words { min-width: 0; }
.person-words h1 {
  margin: 0; font-size: var(--t-title); font-weight: 700;
  letter-spacing: -.03em; text-wrap: balance;
}
.person.ok   .person-words h1 { color: var(--ok); }
.person.warn .person-words h1 { color: var(--warn); }
.person.bad  .person-words h1 { color: var(--bad); }
.person-words p {
  margin: var(--s2) 0 0; color: var(--ink-2); font-size: var(--t-body); text-wrap: pretty;
}

/* --- their screen, drawn as a phone --------------------------------------- */

.glance {
  display: grid;
  /* A fixed track, and this is the whole lesson. It was `minmax(208px, auto)`, and `auto`
     means "as wide as the content would like": the moment a button said "Preguntándole…" or a
     line of explanation appeared underneath, the column grew, the story was shoved sideways
     and the buttons stretched across half the screen. A page that rearranges itself when a
     label changes length is a page nobody trusts.
     Nothing in this column may size it. What varies is text, and text wraps. */
  /* The phone grows with the page but never because of what is written beside it. A fixed
     240px stopped the column jumping when a label changed length — which was the bug — and
     then left a postage stamp in the middle of a wide screen. `clamp` keeps both: the track
     is a function of the viewport and of nothing inside the column. */
  grid-template-columns: clamp(240px, 22vw, 380px) minmax(0, 1fr);
  align-items: start;
  gap: var(--s6);
}
.glance-phone {
  display: flex; flex-direction: column; gap: var(--s4);
  min-width: 0;
}
/* Always there and always the same height, so a two-line answer does not lift everything
   under it. Three lines because the longest thing it says takes three at this width. */
.verb-note { min-height: calc(3 * 1.45em); }
.glance-story { min-width: 0; }

.handset { flex: 0 0 auto; }
.handset { animation: rise .46s .06s cubic-bezier(.2,.7,.3,1) both; }
.handset-screen {
  width: 100%; aspect-ratio: 9 / 20;
  padding: 7px;
  background: #05080a;
  border: 2px solid var(--line);
  border-radius: 26px;
  box-shadow: var(--shadow);
  overflow: hidden;
}
.handset-screen img,
.handset-empty {
  width: 100%; height: 100%;
  border-radius: 19px;
  object-fit: cover; object-position: top;
  display: block;
}
.handset-empty {
  display: grid; place-items: center; padding: var(--s4);
  background: var(--surface);
  color: var(--ink-3); font-size: var(--t-small); text-align: center;
}
.handset-when { margin: var(--s3) 0 0; text-align: center; font-size: var(--t-small); color: var(--ink-2); }

.verbs { display: flex; flex-direction: column; gap: var(--s2); }
.verbs .button { width: 100%; }

/* --- what has happened ---------------------------------------------------- */

.story { list-style: none; margin: 0; padding: 0; }
.story li {
  display: grid; grid-template-columns: 62px minmax(0, 1fr); gap: var(--s3);
  padding: var(--s3) 0;
  border-top: 1px solid var(--line-soft);
}
.story li:first-child { border-top: 0; padding-top: 0; }
.story time {
  font-family: var(--mono); font-size: var(--t-small); color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.story span { font-size: var(--t-body); text-wrap: pretty; }

@media (max-width: 860px) {
  .glance { grid-template-columns: minmax(0, 1fr); }
  .glance-phone { max-width: none; }
  .glance-phone { align-items: center; }
  .verbs { width: 100%; max-width: 320px; }
}

@media (max-width: 620px) {
  .person { flex-direction: column; align-items: flex-start; gap: var(--s3); }
  .face { width: 72px; height: 72px; }
  .settings-link { margin-left: 0; }
}

/* Switching phones, in the header, and only when there is more than one. */
.switch { position: relative; }

.switch-open {
  display: flex; align-items: center; gap: var(--s2);
  font: inherit; font-size: var(--t-small); font-weight: 600;
  padding: var(--s1) var(--s2) var(--s1) var(--s3);
  color: var(--ink); background: transparent;
  border: 1px solid var(--line); border-radius: 999px;
  cursor: pointer; max-width: 44vw;
}
.switch-open:hover { border-color: var(--ink-3); background: var(--surface-2); }
.switch-caret { color: var(--ink-3); font-size: 10px; }
.switch-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.switch-list {
  position: absolute; top: calc(100% + var(--s2)); left: 0; z-index: 20;
  min-width: 232px; padding: var(--s1);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--shadow);
}
.switch-item {
  display: flex; align-items: center; gap: var(--s2); width: 100%;
  padding: var(--s2) var(--s3);
  font: inherit; font-size: var(--t-body); text-align: left;
  color: var(--ink); background: transparent; border: 0; border-radius: var(--r);
  cursor: pointer;
}
.switch-item:hover { background: var(--surface-2); }
.switch-item.on { color: var(--accent); }
.switch-tick { margin-left: auto; }

/* Leaving the daily surface for the settings behind it, and coming back. */
.settings-link {
  align-self: flex-start; margin-left: auto;
  padding: var(--s1) var(--s3);
  color: var(--ink-2); font-size: var(--t-small); font-weight: 550; text-decoration: none;
  border: 1px solid var(--line); border-radius: 999px;
  white-space: nowrap;
}
.settings-link:hover { color: var(--ink); border-color: var(--ink-3); background: var(--surface-2); }
.page-head .lead {
  margin: var(--s2) 0 0; color: var(--ink-2); font-size: var(--t-body);
  max-width: 62ch; text-wrap: pretty;
}
.page-head .back {
  display: inline-block; margin-bottom: var(--s2);
  color: var(--ink-2); font-size: var(--t-small); text-decoration: none;
}
.page-head .back:hover { color: var(--accent); }

/* The header holds a lot on a narrow screen. What survives, in order: the brand, which phone
   you are looking at, and the way out. The rest folds away rather than wrapping into three
   ragged lines, which is what it did. */
@media (max-width: 720px) {
  .top .pill,
  .who .who-mail { display: none; }
  .device-switch { max-width: 38vw; }
}

/* The dot beside a phone's name: how it is, without a word. Paired with the name, never alone. */
.pip {
  width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0;
  background: var(--ok); box-shadow: 0 0 0 3px color-mix(in oklab, var(--ok) 18%, transparent);
}
.pip.quiet { background: var(--bad); box-shadow: 0 0 0 3px color-mix(in oklab, var(--bad) 25%, transparent); }
.pip.off { background: var(--ink-3); box-shadow: none; }

/* The person's own photograph, in the card where their identity lives. */
.own-photo { display: flex; align-items: center; gap: var(--s3); padding-bottom: var(--s4); }
.own-photo img,
.own-photo-empty {
  width: 76px; height: 76px; border-radius: 50%; object-fit: cover;
  border: 2px solid var(--line); background: var(--surface-2);
}
.own-photo-empty {
  display: grid; place-items: center;
  font-size: var(--t-lead); font-weight: 650; color: var(--ink-3);
}

/* Icons inherit the text colour, so a button carrying one belongs to the same drawing as the
   words beside it. They used to be emoji characters, which ignore `color` by design. */
.icon { display: block; }

.icon-button {
  width: 34px; height: 34px; padding: 0;
  display: inline-grid; place-items: center;
  color: var(--ink-3); background: transparent;
  border: 1px solid transparent; border-radius: 999px;
  cursor: pointer;
  transition: color .12s ease, background .12s ease, border-color .12s ease;
}
.icon-button:hover { color: var(--ink); background: var(--surface-2); border-color: var(--line); }
.icon-button.danger:hover { color: var(--bad); background: var(--bad-wash); border-color: color-mix(in srgb, var(--bad) 40%, transparent); }
.icon-button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* What happened when you pressed the button. Under it, in words, always. */
.verb-note {
  margin: var(--s2) 0 0;
  font-size: var(--t-small); color: var(--ink-2); text-wrap: pretty;
}
.verb-note.problem { color: var(--warn); }
.verb-note.working { color: var(--accent); }

/* Unrelated subjects down a page, each with the room to be read. Not the two-up grid, which
   made four different things look like four readings of one. */
.stack-wide { display: flex; flex-direction: column; gap: var(--s6); }

/* A link that acts as a button. Same drawing, because to whoever presses it there is no
   difference and there should not be one on the page either. */
a.button { display: inline-block; text-decoration: none; }
.button.small { padding: var(--s2) var(--s3); font-size: var(--t-small); }

/* An aside: true, worth saying, and not worth the size of the text around it. */
.aside { margin: var(--s3) 0 0; color: var(--ink-3); font-size: var(--t-small); max-width: 62ch; }

/* Words that fold away before a line wraps. */
@media (max-width: 620px) { .wide { display: none; } }

/* Something worth saying that is not the verdict: a version waiting, a warning. Beside the
   text rather than above it, so it reads as one sentence with a way to act on it. */
.notice {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s4); flex-wrap: wrap;
  padding: var(--s4);
  background: var(--accent-wash);
  border: 1px solid var(--accent-deep);
  border-radius: var(--r-lg);
}
.notice-words strong { display: block; font-size: var(--t-body); color: var(--accent); }
.notice-words p { margin: var(--s1) 0 0; color: var(--ink-2); font-size: var(--t-small); max-width: 62ch; }

/* A control the phone in front of you is too old for. Visible, so a family does not see a
   different panel from their sister's, and plainly out of reach. */
.toggle.off { opacity: .4; cursor: default; }
.choice:disabled { opacity: .45; cursor: default; }

/* Which panel this is. Quiet until somebody is looking for it. */
.version { font-family: var(--mono); font-size: var(--t-micro); color: var(--ink-3); }

/* Where an install has got to. It exists because two minutes of an unchanged screen and two
   minutes of nothing happening look exactly alike. */
.stage { margin-top: var(--s3); }
.stage p { margin: 0; color: var(--accent); font-size: var(--t-body); }
.stage-bar {
  margin-top: var(--s2); height: 6px; border-radius: 999px;
  background: var(--surface-2); overflow: hidden;
}
.stage-bar i { display: block; height: 100%; background: var(--accent); transition: width .3s ease; }

/* Button text, a size up. What a 45-year-old reads on a phone in a corridor, not what fits. */
.button { font-size: var(--t-lead); }
.button.small { font-size: var(--t-body); }
/* The two somebody actually came to press. Bigger than everything else because they are the
   reason the page exists; the rest of the page is settings, and a setting is read before it is
   pressed.
   Only these two, and that is a measurement rather than a preference: putting the same size on
   the buttons that sit in a heading row cost 398 pixels of horizontal overflow and started the
   page moving again. A button in a heading has to fit beside a heading. */
.verbs .button { font-size: var(--t-title); padding: var(--s4) var(--s5); }

/* Everything in a heading row wraps under it rather than pushing the page sideways. */
.card-head { flex-wrap: wrap; }
