/* Timeline — auth shell.
   Palette: porcelain / graphite with a single deep-viridian accent.
   System font stack by design: kiosk Pis may have no internet, so the UI
   must never depend on a webfont. Light/dark follows the OS (spec §5). */

:root {
  --paper:   #f3f5f4;
  --card:    #fdfdfc;
  --ink:     #20262b;
  --muted:   #5c6a70;
  --line:    #d7dedb;
  --accent:  #0f6f5c;   /* deep viridian */
  --accent-ink: #ffffff;
  --late:    #b3402f;   /* reserved for LATE items from Phase 3 on */
  --focus:   #0f6f5c;
}
html.dark {
  --paper:  #171c1f;
  --card:   #1f2529;
  --ink:    #e8ecea;
  --muted:  #93a1a6;
  --line:   #323b40;
  --accent: #3aa88f;
  --accent-ink: #0e1412;
  --late:   #d96a58;
  --focus:  #3aa88f;
}

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
body {
  background: var(--paper);
  color: var(--ink);
  font: 16px/1.55 system-ui, "Segoe UI", Roboto, Ubuntu, sans-serif;
  -webkit-font-smoothing: antialiased;
}

.shell {
  min-height: 100%;
  display: grid;
  place-items: center;
  padding: 2rem 1rem;
}

.card {
  width: min(26rem, 100%);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 2rem 2.25rem 2.25rem;
}
.card.wide { width: min(38rem, 100%); }

/* Signature: the timeline track. A quiet promise of the product itself. */
.track {
  display: flex;
  align-items: center;
  gap: 0;
  margin: 0 0 1.75rem;
}
.node {
  width: 10px; height: 10px;
  border-radius: 50%;
  border: 2px solid var(--line);
  background: var(--card);
  flex: none;
}
.node.done { background: var(--line); }
.node.active {
  border-color: var(--accent);
  background: var(--accent);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 18%, transparent);
}
.node + .node { margin-left: 0; }
.track .node:not(:first-child)::before { content: none; }
.track { position: relative; }
.track::before {
  content: "";
  position: absolute;
  left: 4px; right: 4px; top: 50%;
  height: 2px;
  background: var(--line);
  z-index: 0;
}
.node { position: relative; z-index: 1; margin-right: auto; }
.track .node:last-child { margin-right: 0; }

.eyebrow {
  margin: 0 0 .35rem;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
}
h1 {
  margin: 0 0 .6rem;
  font-size: 1.45rem;
  font-weight: 650;
  letter-spacing: -.01em;
}
.lede { margin: 0 0 1.4rem; color: var(--muted); }
.lede a { color: var(--accent); }

form { display: grid; gap: 1rem; }
label {
  display: grid;
  gap: .35rem;
  font-size: .85rem;
  font-weight: 600;
  color: var(--muted);
}
.hint { font-weight: 400; }
input {
  font: inherit;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: .6rem .7rem;
}
input:focus-visible, button:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
}

button {
  font: inherit;
  font-weight: 650;
  border: 0;
  border-radius: 6px;
  padding: .7rem 1rem;
  background: var(--accent);
  color: var(--accent-ink);
  cursor: pointer;
}
button.secondary {
  background: transparent;
  color: var(--accent);
  border: 1px solid var(--line);
}

.error {
  margin: 0 0 1rem;
  padding: .6rem .8rem;
  border-radius: 6px;
  border: 1px solid color-mix(in srgb, var(--late) 40%, transparent);
  background: color-mix(in srgb, var(--late) 10%, transparent);
  color: var(--late);
  font-size: .9rem;
}

@media (prefers-reduced-motion: no-preference) {
  .node.active { transition: box-shadow .4s ease; }
}

/* ---- Phase 2: editor ---- */
.topbar { display:flex; justify-content:space-between; align-items:center; gap:1rem; }
.topbar form { display:inline; }
button.small { padding:.35rem .7rem; font-size:.8rem; }
.inline-form { display:flex; gap:.6rem; margin-top:1.2rem; }
.inline-form input { flex:1; }
.projlist { list-style:none; margin:0 0 .5rem; padding:0; }
.projlist li { display:flex; align-items:center; gap:.8rem;
  padding:.7rem .2rem; border-bottom:1px solid var(--line); }
.projlist a { color:var(--ink); font-weight:650; text-decoration:none; flex:1; }
.projlist a:hover { color:var(--accent); }
.meta { color:var(--muted); font-size:.82rem; }
table.events { width:100%; border-collapse:collapse; font-size:.92rem; }
table.events th { text-align:left; font-size:.72rem; letter-spacing:.1em;
  text-transform:uppercase; color:var(--muted); padding:.4rem .5rem;
  border-bottom:1px solid var(--line); }
table.events td { padding:.6rem .5rem; border-bottom:1px solid var(--line);
  vertical-align:top; }
td.actions { display:flex; gap:.4rem; align-items:center; }
td.actions form { display:inline; }
.badge { display:inline-block; padding:.15rem .55rem; border-radius:999px;
  font-size:.72rem; font-weight:650; border:1px solid var(--line); color:var(--muted); }
.badge.done { border-color:transparent;
  background:color-mix(in srgb, var(--accent) 15%, transparent); color:var(--accent); }
.badge.late { border-color:transparent; background:var(--late); color:#fff; }
.badge.donelate { border-color:var(--late); color:var(--late); }
.btnlink { color:var(--accent); font-weight:650; font-size:.85rem; text-decoration:none; }
.btnlink.solid { display:inline-block; background:var(--accent); color:var(--accent-ink);
  padding:.55rem .9rem; border-radius:6px; }
textarea { font:inherit; color:var(--ink); background:var(--paper);
  border:1px solid var(--line); border-radius:6px; padding:.6rem .7rem; resize:vertical; }
textarea:focus-visible { outline:2px solid var(--focus); outline-offset:1px; }

/* ---- Phase 3: viewer ---- */
.viewwrap { width:min(72rem,100%); align-self:start; }
.shell:has(.viewwrap) { place-items:start center; }
.viewbar { display:flex; justify-content:space-between; align-items:center;
  margin-bottom:1rem; }
.pill { font-size:.78rem; font-weight:650; padding:.25rem .7rem;
  border-radius:999px; }
.pill.warn { background:color-mix(in srgb, var(--late) 12%, transparent);
  color:var(--late); }
.pill.bad { background:var(--late); color:#fff; }
.board { display:grid; gap:1.1rem; }
.trow { background:var(--card); border:1px solid var(--line);
  border-radius:10px; padding:1rem 1.4rem 1.4rem; }
.trow-head { display:flex; align-items:baseline; gap:.7rem; }
.trow-head h2 { margin:0 0 .4rem; font-size:1.05rem; letter-spacing:-.01em; }
.chip { font-size:.72rem; font-weight:650; color:var(--muted);
  border:1px solid var(--line); border-radius:999px; padding:.1rem .55rem; }
.tl { position:relative; height:9.5rem; }
.tl-line { position:absolute; left:0; right:0; top:2.1rem; height:2px;
  background:var(--line); }
.tl-today { position:absolute; left:50%; top:.6rem; bottom:.6rem; width:2px;
  background:var(--accent); opacity:.7; }
.tl-today-label { position:absolute; top:-0.55rem; left:50%;
  transform:translateX(-50%); font-size:.66rem; font-weight:700;
  letter-spacing:.12em; text-transform:uppercase; color:var(--accent);
  background:var(--card); padding:0 .3rem; }
.tnode { position:absolute; top:1.55rem; transform:translateX(-50%);
  /* v0.14.1 field fix: 7.5rem ellipsized modest titles ("Remote
     Configuration Review") on real TVs. Wider ceiling + a third clamp
     line; the alt-row stagger keeps neighbors from colliding. */
  width:clamp(4.6rem, 12vw, 9.5rem); text-align:center; }
.tnode.alt .tlabel { margin-top:2.7rem; }   /* stagger: odd labels drop a row */
.tnode.alt .tlabel::before { content:""; display:block; margin:-2.55rem auto .35rem;
  width:1px; height:2.2rem; background:var(--line); }
.tnode .dot { display:block; margin:0 auto; width:14px; height:14px;
  border-radius:50%; background:var(--card); border:3px solid var(--muted); }
.tnode.upcoming .dot { border-color:var(--accent); }
.tnode.today .dot { box-shadow:0 0 0 4px color-mix(in srgb, var(--accent) 25%, transparent); }
.tnode.late .dot { border-color:var(--late); background:var(--late); }
.tnode.complete .dot { border-color:var(--accent); background:var(--accent); }
.tnode.complete-late .dot { border-color:var(--late); background:var(--card); }
.tlabel { margin-top:.45rem; }
.ttitle { font-size:.82rem; font-weight:650; line-height:1.15;
  display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical;
  overflow:hidden; overflow-wrap:anywhere; }
.tnode.complete .ttitle, .tnode.complete-late .ttitle { color:var(--muted); }
.tdate { font-size:.72rem; color:var(--muted); }
.tl-empty { position:absolute; inset:0; display:grid; place-items:center;
  color:var(--muted); font-size:.9rem; }

/* ---- Phase 4: cycling ---- */
.trow.pagerow { transition-property:opacity; transition-timing-function:ease; }
.trow.faded { opacity:0; }
.trow-head .spacer { flex:1; }
.pager { display:flex; align-items:center; gap:.5rem; }
.pgbtn { background:transparent; border:1px solid var(--line); color:var(--muted);
  border-radius:6px; width:1.7rem; height:1.7rem; padding:0; line-height:1;
  font-size:1rem; font-weight:700; cursor:pointer; }
.pgbtn:hover { color:var(--accent); border-color:var(--accent); }
.pgdots { display:inline-flex; align-items:center; gap:.35rem; }
.pgdot { width:7px; height:7px; border-radius:50%; background:var(--line);
  display:inline-block; }
.pgring { width:18px; height:18px; display:inline-block; }
.pgring-core { fill:var(--accent); }
.pgring-sweep { fill:none; stroke:var(--accent); stroke-width:2;
  stroke-dasharray:44; stroke-dashoffset:44; transform:rotate(-90deg);
  transform-origin:center; animation-name:pgsweep; animation-timing-function:linear;
  animation-fill-mode:forwards; }
@keyframes pgsweep { to { stroke-dashoffset:0; } }
.pgcount { font-size:.74rem; font-weight:650; color:var(--muted);
  font-variant-numeric:tabular-nums; }
@media (prefers-reduced-motion: reduce) {
  .pgring-sweep { animation:none; stroke-dashoffset:0; }
  .trow.pagerow { transition:none; }
}

/* ---- Phase 5: admin, palettes, branding ---- */
body[data-palette="ember"] { --accent:#b4552d; --focus:#b4552d; }
html.dark body[data-palette="ember"] { --accent:#e08a5e; --accent-ink:#1b0f08; --focus:#e08a5e; }
body[data-palette="cobalt"] { --accent:#31589e; --focus:#31589e; }
html.dark body[data-palette="cobalt"] { --accent:#7d9fd8; --accent-ink:#0b1220; --focus:#7d9fd8; }
body[data-palette="plum"] { --accent:#6d3a6d; --focus:#6d3a6d; }
html.dark body[data-palette="plum"] { --accent:#b487b4; --accent-ink:#160d16; --focus:#b487b4; }

.ok { margin:0 0 1rem; padding:.6rem .8rem; border-radius:6px;
  border:1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  background:color-mix(in srgb, var(--accent) 10%, transparent);
  color:var(--accent); font-size:.9rem; }
.grouphead { margin:1.6rem 0 .6rem; font-size:.8rem; font-weight:700;
  letter-spacing:.12em; text-transform:uppercase; color:var(--muted); }
.settings label { margin-bottom:.4rem; }
select { font:inherit; color:var(--ink); background:var(--paper);
  border:1px solid var(--line); border-radius:6px; padding:.5rem .6rem; }
.brandlogo { max-height:var(--logo-h, 56px); max-width:320px; }
.brandlogo.sm { max-height:calc(var(--logo-h, 56px) * .6); }
.brandline { display:flex; align-items:center; gap:.7rem; }
.userrow { border-bottom:1px solid var(--line); padding:.9rem 0; }
.userhead { display:flex; gap:.7rem; align-items:baseline; margin-bottom:.5rem; }
.useractions { display:flex; flex-wrap:wrap; gap:.6rem; align-items:center; }
.useractions form, .grants { display:flex; gap:.4rem; align-items:center;
  flex-wrap:wrap; }
.grants { margin-top:.5rem; }
.check { display:inline-flex; gap:.3rem; align-items:center; font-weight:400;
  font-size:.85rem; color:var(--ink); }
table.audit td.change { font-size:.78rem; font-family:ui-monospace,monospace;
  word-break:break-word; max-width:22rem; }

/* ---- Phase 6: pairing + kiosk mode ---- */
.pairing { text-align:center; }
.paircode { font-size:3.4rem; letter-spacing:.35em; margin:.4rem 0 1rem;
  font-variant-numeric:tabular-nums; padding-left:.35em; }
body.kiosk { font-size:19px; }
body.kiosk .shell { padding:1.2rem; }
body.kiosk .pgbtn { display:none; }           /* TVs are non-interactive */
body.kiosk .viewbar .eyebrow a { pointer-events:none; }
body.kiosk .trow { padding:1.2rem 1.6rem 1.7rem; }
body.kiosk .tl { height:11rem; }
body.kiosk .ttitle { font-size:.95rem; }
body.kiosk .tdate { font-size:.82rem; }
body.kiosk .trow-head h2 { font-size:1.25rem; }


/* ---- v0.8.2: nav bar, theme forcing, spacing feedback ---- */
.pagewrap { width:min(72rem,100%); align-self:start; }
.shell:has(.pagewrap) { place-items:start center; }
.pagewrap .card { width:100%; }
.topnav { display:flex; align-items:center; gap:.45rem; flex-wrap:wrap;
  margin-bottom:1rem; }
.topnav form { display:inline; margin:0; }
.navbtn { display:inline-block; padding:.45rem .85rem; border-radius:7px;
  background:var(--card); border:1px solid var(--line); color:var(--ink);
  font-size:.85rem; font-weight:650; text-decoration:none; cursor:pointer;
  font-family:inherit; line-height:1.2; }
.navbtn:hover { border-color:var(--accent); color:var(--accent); }
.navbtn.ghost { background:transparent; color:var(--muted); }
.topnav .spacer { flex:1; }
.brandlogo.nav { max-height:calc(var(--logo-h, 56px) * .6); margin-right:.4rem; }
.viewwrap .topnav { margin-bottom:.6rem; }
body.kiosk .topnav { display:none; }

/* ---- v0.9.0: batch entry ---- */
table.batch input { width:100%; min-width:0; padding:.4rem .5rem; }
table.batch input[type="date"] { width:9.5rem; }
table.batch input[type="time"] { width:6.5rem; }
table.batch td { padding:.35rem .35rem; }
td.delcell { text-align:center; }
tr.newrow td { background:color-mix(in srgb, var(--accent) 4%, transparent); }
.batchactions { display:flex; gap:.7rem; margin-top:1rem; }
.problemlist { margin:.4rem 0 0; padding-left:1.2rem; }
.problemlist li { margin:.2rem 0; }


/* ---- v0.10.0: on-time metric + unscored ---- */
.tnode.unscored .dot { border-color:var(--muted); background:var(--line); }
.ontime { display:inline-flex; align-items:center; gap:.4rem; margin-left:.9rem; }
.ontime-ring { width:22px; height:22px; }
.ontime-track { fill:none; stroke:var(--line); stroke-width:3.5; }
.ontime-late { fill:none; stroke:var(--late); stroke-width:3.5; opacity:.85; }
.ontime-arc { fill:none; stroke:var(--accent); stroke-width:3.5;
  transform:rotate(-90deg); transform-origin:center; stroke-linecap:butt; }
.ontime-pct { font-size:.85rem; font-weight:700;
  font-variant-numeric:tabular-nums; }
.ontime.early .ontime-pct { color:var(--accent); }
.ontime-label { font-size:.72rem; font-weight:650; letter-spacing:.08em;
  text-transform:uppercase; color:var(--muted); }
.ontime.empty .ontime-pct { color:var(--muted); font-weight:650; }
body.kiosk .ontime-ring { width:28px; height:28px; }
body.kiosk .ontime-pct { font-size:1.05rem; }
@media (max-width: 700px) { .ontime-label { display:none; } }


/* ---- v0.13.0 ---- */
.viewhead { display:flex; align-items:center; gap:.8rem; }
.viewtitle { margin:0; font-size:1rem; font-weight:700; letter-spacing:.18em;
  text-transform:uppercase; color:var(--muted); }
body.kiosk .viewtitle { font-size:1.35rem; }
body.kiosk .brandlogo.sm { max-height:calc(var(--logo-h, 56px) * .9); }
.clock { font-size:1.05rem; font-weight:700; font-variant-numeric:tabular-nums;
  color:var(--ink); margin-left:auto; padding-left:1rem; }
body.kiosk .clock { font-size:1.6rem; }
.viewbar { gap:1rem; }
.sitefoot { position:fixed; right:.9rem; bottom:.6rem; font-size:.7rem;
  color:var(--muted); background:color-mix(in srgb, var(--paper) 82%, transparent);
  padding:.15rem .5rem; border-radius:6px; z-index:5; }
.sitefoot a { color:var(--muted); font-weight:650; text-decoration:none; }
.sitefoot a:hover { color:var(--accent); }

/* ---- v0.14.0: client portal flags on internal surfaces ---- */
.badge.client { border-color:var(--accent); color:var(--accent); }
.badge.est { border-color:var(--muted); color:var(--muted); border-style:dashed; }
.est { color:var(--muted); font-style:italic; }
.tnode.estimated .dot { border-color:var(--muted); border-style:dashed; background:var(--card); }
.tnode.estimated .tdate { font-style:italic; }
.inlineform { margin-top:.8rem; display:flex; align-items:center; gap:.6rem; }

.revealbox { border:2px solid var(--accent); border-radius:12px; padding:1rem 1.2rem;
  margin:1rem 0 1.4rem; background:color-mix(in srgb, var(--accent) 7%, var(--card)); }
.revealbox .secret code { font-size:1.05rem; user-select:all; word-break:break-all; }
.rowform { display:flex; gap:1rem; align-items:end; flex-wrap:wrap; }
.rowform label { margin:0; }

/* ---- v0.14.1 field fixes ---- */
.jobnum { font-size:1rem; font-weight:600; color:var(--muted); white-space:nowrap; }
.jobform { margin:.3rem 0 1rem; }

/* ---- v0.15.0 ---- */
.issuebody { white-space:pre-wrap; max-width:34rem; }
.resolvedrow { opacity:.55; }
textarea { width:100%; font:inherit; background:var(--bg); color:var(--ink);
  border:1px solid var(--line); border-radius:8px; padding:.6rem; }

/* ---- v0.15.1: settings tabs ---- */
.tabbar { display:flex; gap:.35rem; flex-wrap:wrap; margin:.4rem 0 1.1rem;
  border-bottom:1px solid var(--line); padding-bottom:.55rem; }
.tabbtn { font:inherit; font-size:.86rem; font-weight:600; cursor:pointer;
  background:transparent; color:var(--muted); border:1px solid var(--line);
  border-radius:999px; padding:.32rem .85rem; }
.tabbtn:hover { color:var(--ink); }
.tabbtn.active { background:var(--accent); border-color:var(--accent);
  color:#fff; }
/* hiding only engages when JS added .tabbed — no-JS keeps the long page */
.tabbed .tabpane { display:none; }
.tabbed .tabpane.active { display:block; }

/* ---- v0.15.1: archived shelf ---- */
.archshelf { margin-top:1.4rem; border-top:1px solid var(--line); padding-top:.9rem; }
.archshelf summary { cursor:pointer; font-weight:600; color:var(--muted); }
.projlist.archived li span:first-child { color:var(--muted); }
button.danger { background:transparent; border:1px solid var(--late);
  color:var(--late); border-radius:8px; cursor:pointer; font:inherit; }
button.danger:hover { background:var(--late); color:#fff; }
button.danger.small { font-size:.8rem; padding:.25rem .7rem; }

/* ---- v0.15.1: mobile (internal pages + viewer) ----
   The viewer's wall-display layout is a horizontal strip of absolutely
   positioned nodes. On a phone that geometry has no room to breathe, so
   ≤620px the SAME DOM re-lays as a vertical timeline: flex column, nodes
   in chronological DOM order, the today marker re-slotted between past
   and future via flex `order` (past states 0, today 1, upcoming 2). The
   JS-set style.left survives harmlessly — `left` is ignored once
   position is static. Viewing style changes; the data and code do not. */
@media (max-width: 620px) {
  .tl { height:auto; display:flex; flex-direction:column; gap:1rem;
    padding:.4rem 0 .2rem 1.3rem; }
  .tl-line { left:5px; right:auto; top:0; bottom:0; width:2px; height:auto; }
  .tl-today { position:static; width:auto; order:1; opacity:1;
    border-top:2px solid var(--accent); margin-left:-1.3rem; height:0; }
  .tl-today-label { top:-.62rem; left:0; transform:none; }
  .tnode { position:static; transform:none; width:auto; text-align:left;
    display:flex; gap:.75rem; align-items:flex-start; order:0; }
  .tnode.upcoming { order:2; }
  .tnode .dot { margin:.2rem 0 0 -1.62rem; flex:0 0 auto; position:relative;
    z-index:1; }
  .tnode.alt .tlabel { margin-top:0; }
  .tnode.alt .tlabel::before { display:none; }
  .tlabel { margin-top:0; }
  .ttitle { -webkit-line-clamp:4; }
  .tl-empty { position:static; transform:none; margin-left:-1.3rem; }
  .viewbar { flex-wrap:wrap; gap:.4rem; }

  /* internal pages: cards use the width, tables scroll instead of
     crushing, forms stack */
  .shell { padding:.8rem .6rem; }
  .card, .card.wide { padding:1.1rem .9rem; }
  table.events { display:block; overflow-x:auto; white-space:nowrap; }
  table.events td.issuebody { white-space:pre-wrap; min-width:14rem; }
  .rowform { flex-direction:column; align-items:stretch; }
  .rowform label { width:100%; }
  .projlist li { flex-wrap:wrap; row-gap:.4rem; }
  .jobform { flex-direction:column; align-items:stretch; }
}

/* ---- v0.16: 2FA ---- */
.rcodes { columns:2; list-style:none; padding:0; margin:.6rem 0; }
.rcodes code { font-size:1.02rem; user-select:all; }
.authcard { max-width:26rem; margin:8vh auto; }

/* ---- v0.16.1: topbar + slide-out drawer (all screen sizes) ---- */
.topbar { display:flex; align-items:center; gap:.7rem; padding:.45rem .2rem;
  margin-bottom:.9rem; border-bottom:1px solid var(--line); }
.topbar-brand { font-weight:700; letter-spacing:-.01em; color:var(--ink);
  text-decoration:none; }
.topbar .spacer { flex:1; }
.topbar-account { max-width:9rem; overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap; }
.navtoggle { display:inline-flex; flex-direction:column; justify-content:center;
  gap:4px; width:44px; height:44px; align-items:center; border-radius:8px;
  border:1px solid var(--line); background:var(--card); cursor:pointer;
  text-decoration:none; flex:0 0 auto; }
.navtoggle:hover { border-color:var(--accent); }
.navtoggle .bar { width:18px; height:2px; background:var(--ink);
  border-radius:1px; }
.navtoggle.close { border:0; background:transparent; align-self:flex-end;
  margin:.2rem .2rem 0 0; }
.navtoggle.close .x { font-size:1.7rem; color:var(--muted); line-height:1; }
.drawer { position:fixed; top:0; left:0; bottom:0; z-index:60;
  width:min(19rem, 85vw); background:var(--card);
  border-right:1px solid var(--line); box-shadow:0 0 40px rgba(0,0,0,.25);
  display:flex; flex-direction:column; gap:.15rem; padding:.4rem .8rem 1.2rem;
  transform:translateX(-105%); transition:transform .22s ease;
  overflow-y:auto; }
.drawer.open, .drawer:target { transform:translateX(0); }
.drawer-backdrop { position:fixed; inset:0; z-index:55;
  background:rgba(0,0,0,.35); }
.drawerhead { font-size:.68rem; font-weight:700; letter-spacing:.12em;
  text-transform:uppercase; color:var(--muted); margin:.9rem 0 .15rem .4rem; }
.drawerlink { display:block; padding:.65rem .8rem; border-radius:8px;
  color:var(--ink); text-decoration:none; font-weight:600; font-size:.95rem;
  min-height:44px; box-sizing:border-box; }
.drawerlink:hover { background:color-mix(in srgb, var(--accent) 10%, transparent);
  color:var(--accent); }
.drawer form { margin:0; }
.drawerlink.asbutton { width:100%; text-align:left; border:0;
  background:transparent; cursor:pointer; font:inherit; font-weight:600; }
body.kiosk .topbar, body.kiosk .drawer, body.kiosk .drawer-backdrop { display:none; }
.viewwrap .topbar { margin-bottom:.5rem; }
@media (max-width: 620px) {
  .topbar { padding:.3rem 0; margin-bottom:.6rem; position:sticky; top:0;
    background:var(--bg); z-index:40; }
  .topbar-brand { font-size:.95rem; }
  /* touch targets + iOS no-zoom inputs */
  input, select, textarea, button { font-size:16px; }
  .navbtn, button.secondary, .drawerlink { min-height:44px; }
  .tabbar { flex-wrap:nowrap; overflow-x:auto; -webkit-overflow-scrolling:touch;
    padding-bottom:.4rem; }
  .tabbtn { white-space:nowrap; }
}

/* ---- v0.16.1: drawer theme switch ---- */
.themerow { display:flex; gap:.3rem; margin:.2rem .3rem .6rem; }
.themebtn { flex:1; font:inherit; font-size:.82rem; font-weight:600;
  padding:.45rem .3rem; border-radius:8px; border:1px solid var(--line);
  background:transparent; color:var(--muted); cursor:pointer; min-height:40px; }
.themebtn.active { background:var(--accent); border-color:var(--accent);
  color:#fff; }
.themebtn:hover { border-color:var(--accent); }

/* ---- v1.0.0: client contact cell ---- */
.contactform { display:flex; gap:.35rem; align-items:center; flex-wrap:wrap; }
.contactform input[type=email] { width:13rem; }
.contactcell .hint { display:block; max-width:16rem; }

/* ---- v1.0.0: dark-logo swap, driven purely by theme state ---- */
/* rc7: the swap applies EVERYWHERE a logo appears, not only the topbar.
   Scoping these to a.topbar-logolink meant the login, setup, pairing and
   kiosk screens always served the light-mode file — a dark-ink wordmark
   on a dark page. The .logo-light class is only emitted when a dark file
   exists (see _brandimg.html), so these rules can never blank a
   single-file install and no :has()/:only-child trickery is needed. */
.logo-dark { display:none; }
html[data-theme="dark"] .logo-light { display:none; }
html[data-theme="dark"] .logo-dark { display:inline; }
@media (prefers-color-scheme: dark) {
  html[data-theme="auto"] .logo-light { display:none; }
  html[data-theme="auto"] .logo-dark { display:inline; }
}
.darkpreview { background:#1a2029; padding:8px 12px; border-radius:8px; }
.topbar-logolink { display:inline-flex; align-items:center; }

/* ---- v1.0.0: viewport overflow audit (the forced-zoom-out fix) ----
   Anything wider than the screen forces mobile browsers to scale the
   whole page down. Belt-and-braces: media never exceeds the viewport,
   long unbroken strings (TOTP keys, links, otpauth URIs) wrap, and the
   reveal boxes can't push the layout. */
img { max-width:100%; height:auto; }
.topbar img.brandlogo { max-height:var(--logo-h, 40px); width:auto; max-width:46vw; }
code, .secret code, .revealbox code { overflow-wrap:anywhere; word-break:break-all; }
.revealbox, .card, .pcard { min-width:0; }
pre { white-space:pre-wrap; overflow-wrap:anywhere; }

/* ---- v1.2.0 ---- */
.lockedalt { margin-top:.7rem; }

/* ---- rc7: link contrast on muted lines ----
   "Forgot password?" and "Request access" sat inside .meta, which is
   deliberately muted for secondary TEXT — but a muted link is an
   invisible link, and those two are the only way in for someone locked
   out or new. Links inside muted text now take full ink with a visible
   underline, and the auth-card versions get a touch more size. */
.meta a { color:var(--ink); text-decoration:underline;
  text-underline-offset:.18em; font-weight:600; }
.meta a:hover, .meta a:focus-visible { color:var(--accent); }
.authcard .meta a { font-size:.95rem; }
.authcard .authlinks { margin-top:1rem; display:flex; gap:1rem;
  flex-wrap:wrap; }
