/* LIB Visa Portal */
:root {
  --navy: #16305c;
  --navy-2: #1f4287;
  --accent: #e8b23a;
  --accent-dark: #c69422;
  /* --accent and --accent-dark are display golds: on white they measure 2.74:1
     and 3.35:1, so neither may set TEXT. This one is 4.62:1 and is the only
     gold allowed to carry words on a light ground. */
  --gold-ink: #8a6410;
  --bg: #f5f7fb;
  --card: #ffffff;
  --ink: #1c2434;
  --muted: #64708a;
  --line: #dfe5ef;
  --ok: #1d9a6c;        /* icons, borders, large text */
  --ok-text: #147a52;   /* 4.83:1 on --ok-bg — use for text in green badges */
  --warn: #c8501d;
  --info-bg: #eef4ff;
  --warn-bg: #fdf1e7;
  --ok-bg: #e9f7f0;
  /* Referenced by the costs page's grand-total card, which had been carrying an
     inline fallback because the token did not exist. */
  --mint: #e7f4ee;
  --radius: 14px;

  /* ---- type scale ----
     Six steps, no more. The old sheet carried 24 distinct sizes with nothing
     deciding between them, and the top four existed only to enlarge emoji.
     Japanese needs a slightly larger optical size than Latin at the same nominal
     px, which is why the body step is 15px rather than 14. */
  --t-xs: 12.5px;   /* meta, timestamps, table footnotes */
  --t-sm: 13.5px;   /* dense rows, badges, secondary controls */
  --t-md: 15px;     /* body — the default */
  --t-lg: 17px;     /* card headings */
  --t-xl: 21px;     /* section headings */
  --t-2xl: 26px;    /* page title */

  /* ---- spacing scale ----
     16 vertical spacing values and 30+ padding pairs were improvising around
     the absence of this. */
  --s-1: 4px;
  --s-2: 8px;
  --s-3: 12px;
  --s-4: 16px;
  --s-5: 24px;
  --s-6: 32px;
  --s-7: 48px;

  /* ---- radius scale ---- (was 9 different values) */
  --r-sm: 8px;
  --r-md: 10px;
  --r-lg: 14px;
  --r-pill: 999px;

  /* The comfortable measure for running prose. Japanese sets denser than Latin,
     so this is expressed in ch of the Latin body face and lands near 42 Japanese
     characters — both inside a readable line. */
  --measure: 68ch;
  --shadow: 0 2px 10px rgba(22, 48, 92, .08);
  --wa: #118546;         /* white text 4.70:1 — the previous #128c4b measured 4.30:1 */
  --wa-bright: #25d366;  /* brand green for icon accents only */
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: "Segoe UI", "Hiragino Sans", "Yu Gothic UI", Meiryo, system-ui, sans-serif;
  font-size: var(--t-md);
  background: var(--bg);
  color: var(--ink);
  line-height: 1.65;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  /* The default (line-break: auto) lets Chrome break a Japanese line BEFORE the
     prolonged sound mark and small kana, so 「カレンダー」 wrapped as 「カレンダ /
     ー」. strict forbids those, which is the rule Japanese typesetting expects. */
  line-break: strict;
  word-break: normal;
  /* strict only stops the ー being orphaned; Japanese still wraps between any two
     kana, so the word was merely split one character earlier. auto-phrase breaks
     at phrase boundaries instead, keeping 「カレンダー」 whole. Chrome 119+ and
     Safari 18.4+; anywhere else this declaration is dropped and `normal` stands. */
  word-break: auto-phrase;
  overflow-wrap: break-word;
}
a { color: var(--navy-2); text-decoration: none; }

/* ---------- top bar ---------- */
#topbar {
  position: sticky; top: 0; z-index: 50;
  display: flex; align-items: center; gap: 18px;
  padding: 10px 22px;
  background: var(--navy);
  color: #fff;
  box-shadow: 0 2px 8px rgba(0,0,0,.18);
  flex-wrap: wrap;
}
.brand { display: flex; align-items: center; gap: 10px; color: #fff; font-size: 19px; }
.brand-mark { font-size: 26px; }
.brand-name b { color: var(--accent); }
#mainnav { display: flex; gap: 4px; flex-wrap: wrap; flex: 1; }
#mainnav a {
  color: #d7e0f2; padding: 7px 13px; border-radius: 8px; font-size: 14.5px;
}
#mainnav a:hover { background: rgba(255,255,255,.12); color: #fff; }
#mainnav a.active { background: rgba(255,255,255,.18); color: #fff; font-weight: 600; }
.nav-count {
  display: inline-block; min-width: 18px; padding: 0 5px; margin-left: 4px;
  background: #c0392b; color: #fff; border-radius: 999px;
  font-size: 11px; font-weight: 700; line-height: 18px; text-align: center;
}
/* On a 1366px office laptop the twelve labels wrapped into ~3 rows inside the
   sticky header, eating a fifth of the viewport, and the hamburger that would
   fix it only appears below 980px. Give the nav its own full-width row instead:
   stable positions, nothing hidden, and a SHORTER header than before. */
@media (min-width: 981px) {
  #mainnav {
    flex: 0 0 100%; order: 10; flex-wrap: nowrap; overflow-x: auto;
    margin-top: 4px; padding-top: 6px; border-top: 1px solid rgba(255,255,255,.12);
    scrollbar-width: thin;
  }
  #mainnav a { white-space: nowrap; }
}
.topbar-right { display: flex; align-items: center; gap: 10px; }
.lang-switch { display: flex; background: rgba(255,255,255,.14); border-radius: 8px; overflow: hidden; }
.lang-switch button {
  /* 日本語 and EN come from different faces with different vertical metrics, so
     padding alone left the Japanese label sitting off the others' baseline.
     One height, and the label centred inside it. */
  border: 0; background: transparent; color: #d7e0f2; cursor: pointer;
  font-size: 13px; line-height: 1;
  height: 30px; padding: 0 11px;
  display: inline-flex; align-items: center; justify-content: center;
  font-family: inherit;
}
.lang-switch button.active { background: var(--accent); color: #1c2434; font-weight: 700; }
.icon-btn {
  /* On the navy bar these inherit the global link colour (--navy-2), which is
     1.36:1 against it. That was invisible while the content was a colour emoji;
     a currentColor icon simply disappears. Match the nav links. */
  color: #d7e0f2;
  font-size: 18px; padding: 4px 6px; border-radius: 8px;
  min-width: 44px; min-height: 44px; display: inline-flex; align-items: center; justify-content: center;
}
.icon-btn:hover, .icon-btn:focus-visible { background: rgba(255,255,255,.12); color: #fff; }
.sos-link {
  color: #fff; background: #c0392b; border-radius: 999px; padding: 5px 13px; font-size: 13px; font-weight: 700;
  white-space: nowrap;
  /* The pill carries a mark and a word; below 720px the word is hidden and the
     mark has to stand on its own, so lay them out as a row rather than relying
     on inline flow and a space that disappears with the label. */
  display: inline-flex; align-items: center; gap: 6px;
}
.sos-link:hover { filter: brightness(1.12); }
.emergency-hero {
  background: linear-gradient(115deg, #7a1f14, #c0392b); color: #fff; border-radius: 18px;
  padding: 30px 32px; margin-bottom: 22px;
}
.emergency-hero h1 { margin: 0 0 8px; font-size: 26px; }
.emergency-hero p { margin: 0 0 16px; color: #ffd9d2; max-width: 700px; }
.tip-item { display: flex; gap: 12px; padding: 12px 14px; border: 1px solid var(--line); border-radius: 10px; margin-bottom: 8px; background: var(--card); }
.tip-item .tno { flex-shrink: 0; font-size: 18px; }
.tip-item .tt { font-weight: 700; font-size: 15px; }
.tip-item .td { font-size: 14px; color: #3a4459; margin-top: 2px; }
.step-shot { margin-top: 10px; }
.step-shot img {
  max-width: 100%; max-height: 260px; border: 1px solid var(--line); border-radius: 8px;
  cursor: zoom-in; box-shadow: var(--shadow); display: block;
}
.step-shot .cap { font-size: 12px; color: var(--muted); margin-top: 4px; }

/* ---------- walkthrough mode ---------- */
.modal-backdrop.gate    { z-index: 10002; }
.modal-backdrop.relogin { z-index: 10003; }
.modal-backdrop.wt-zoom { z-index: 10004; }
.wt-backdrop {
  position: fixed; inset: 0; background: rgba(12, 20, 38, .96); z-index: 10001;
  display: flex; flex-direction: column; color: #fff;
}
.wt-top {
  display: flex; align-items: center; gap: 14px; padding: 14px 22px;
  border-bottom: 1px solid rgba(255,255,255,.14); flex-wrap: wrap;
}
.wt-top .wt-title { font-weight: 800; font-size: 16px; flex: 1; min-width: 200px; }
.wt-top .wt-count { font-size: 13.5px; color: #b9c6de; white-space: nowrap; }
.wt-close { border: 0; background: rgba(255,255,255,.14); color: #fff; border-radius: 8px; padding: 7px 14px; cursor: pointer; font-size: 14px; }
.wt-progress { height: 5px; background: rgba(255,255,255,.12); }
.wt-progress .fill { height: 100%; background: var(--accent); transition: width .25s; }
.wt-body {
  flex: 1; display: flex; gap: 26px; padding: 22px 30px; overflow: auto; align-items: flex-start;
}
.wt-imgbox {
  flex: 1.4; min-width: 0; display: flex; align-items: center; justify-content: center; align-self: stretch;
}
.wt-imgbox img {
  max-width: 100%; max-height: calc(100vh - 220px); border-radius: 10px;
  box-shadow: 0 10px 44px rgba(0,0,0,.55); cursor: zoom-in; background: #fff;
}
.wt-noimg {
  border: 2px dashed rgba(255,255,255,.25); border-radius: 14px; padding: 40px 30px;
  color: #b9c6de; font-size: 15px; text-align: center; max-width: 420px;
}
.wt-text { flex: 1; min-width: 280px; max-width: 460px; }
.wt-text .num {
  display: inline-flex; width: 38px; height: 38px; border-radius: 50%; background: var(--accent); color: #1c2434;
  align-items: center; justify-content: center; font-weight: 800; font-size: 17px; margin-bottom: 10px;
}
.wt-text h2 { margin: 0 0 10px; font-size: 21px; line-height: 1.4; }
.wt-text .d { font-size: 15px; line-height: 1.75; color: #dce5f5; }
.wt-text .tip { background: rgba(90, 140, 255, .18); border-radius: 10px; padding: 10px 14px; margin-top: 14px; font-size: 14px; }
.wt-text .warn { background: rgba(255, 120, 60, .22); border-radius: 10px; padding: 10px 14px; margin-top: 14px; font-size: 14px; }
.wt-nav {
  display: flex; gap: 12px; align-items: center; justify-content: center; flex-wrap: wrap;
  padding: 14px 22px 20px; border-top: 1px solid rgba(255,255,255,.14);
}
.wt-nav button {
  border: 0; border-radius: 10px; padding: 12px 22px; font-size: 15px; font-weight: 700; cursor: pointer;
}
.wt-nav .wt-prev { background: rgba(255,255,255,.15); color: #fff; }
.wt-nav .wt-done { background: #177a55; color: #fff; }
.wt-nav .wt-next { background: var(--accent); color: #1c2434; }
.wt-nav button:disabled { opacity: .35; cursor: default; }
.wt-hint { width: 100%; text-align: center; font-size: 12px; color: #8fa2c4; }
.wt-btn-row { margin: 4px 0 12px; }
@media (max-width: 820px) {
  .wt-body { flex-direction: column; align-items: stretch; }
  .wt-text { max-width: none; }
}

/* ---------- layout ---------- */
#view { flex: 1; width: 100%; max-width: 1120px; margin: 0 auto; padding: 26px 20px 100px; }
.page-title {
  font-size: var(--t-2xl);
  /* 800 exists only in the Latin faces — the Japanese stack has no such weight,
     so 700/800 were the same pixel in the Japanese build and the distinction
     carried nothing. One bold, used consistently. */
  font-weight: 700;
  margin: var(--s-1) 0 var(--s-1);
  color: var(--navy);
  letter-spacing: .01em;
  display: flex;
  align-items: center;
  gap: var(--s-2);
}
.page-sub {
  color: var(--muted);
  margin-bottom: var(--s-5);
  font-size: var(--t-md);
  /* #14: this ran the full 1080px column — about 120 Latin characters a line. */
  max-width: var(--measure);
}
.grid { display: grid; gap: 16px; }
.grid.cols-2 { grid-template-columns: repeat(auto-fill, minmax(min(340px, 100%), 1fr)); }
.grid.cols-3 { grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr)); }

.card {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 18px 20px; box-shadow: var(--shadow);
}
.card.clickable { cursor: pointer; transition: transform .12s, box-shadow .12s; display: block; color: var(--ink); }
.card.clickable:hover { transform: translateY(-2px); box-shadow: 0 6px 18px rgba(22,48,92,.14); }
.card h3 {
  margin: 0 0 var(--s-1);
  font-size: var(--t-lg);
  font-weight: 700;
  color: var(--navy);
  /* NOT display:flex. A flex container lays its children out by
     justify-content and ignores the inherited text-align, so the centred
     support cards had centred icons and centred body text with a LEFT-aligned
     heading between them. The icon aligns itself: .vh-i already carries
     vertical-align, so normal inline flow is correct here. */
}
.card h3 .vh-i { margin-right: var(--s-2); }
.card .icon { font-size: 26px; margin-bottom: 8px; display: block; }
.card p.desc { margin: 0; color: var(--muted); font-size: 13.5px; }

.badge {
  display: inline-block; padding: 2px 10px; border-radius: 999px; font-size: 12px; font-weight: 600;
  background: var(--info-bg); color: var(--navy-2); margin-right: 6px; margin-bottom: 4px;
}
.badge.portal-tka { background: #e9f0e2; color: #3c6b1f; }
.badge.portal-evisa { background: #e7eefc; color: #1f4287; }
.badge.portal-office { background: #f3e9fc; color: #6b2fa0; }
.badge.warn { background: var(--warn-bg); color: #a84314; }

/* ---------- hero ---------- */
.hero {
  background: linear-gradient(120deg, var(--navy) 0%, var(--navy-2) 70%);
  color: #fff; border-radius: 18px; padding: 34px 34px 30px; margin-bottom: 26px;
  position: relative; overflow: hidden;
}
.hero h1 { margin: 0 0 10px; font-size: 30px; line-height: 1.3; }
.hero p {
  margin: 0 0 20px; color: #cfdaf0; max-width: 640px; font-size: 15.5px;
  /* This paragraph wrapped to three lines with 「できます。」 alone on the last one.
     balance asks the browser to even the lines out instead of filling each one to
     the edge and dropping the remainder, which is what leaves a stub. It applies
     to short blocks only (browsers cap it a few lines in), which is exactly what
     a hero paragraph is. Ignored where unsupported, so the fallback is today's
     wrapping. */
  text-wrap: balance;
}
.hero .hero-actions { display: flex; gap: 12px; flex-wrap: wrap; }
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  border: 0; border-radius: 10px; padding: 11px 20px; font-size: 15px; font-weight: 700;
  cursor: pointer; text-decoration: none; transition: filter .12s;
  /* Height was left to whatever the content produced, so four buttons sitting in
     one roster row measured 30.8, 33.3, 36.0 and 30.8px: a <button> takes the UA
     line-height while an <a> inherits the body's 1.65, and an icon-only button is
     sized by the 1.05em <svg> instead of a text line box. Pin both ends — an
     explicit line-height for the text, a min-height for the box — so a button is
     the same size whether it holds a word, an icon, or both. */
  line-height: 1.2;
  /* The floor has to clear the tallest single-line content, which is Japanese:
     the CJK faces carry more ascent+descent than the Latin ones, so 編集 came out
     0.9px taller than an icon at the same font size. Above the floor the box
     stops depending on what is inside it. */
  min-height: 44px;
  /* Inline-level buttons align on their BASELINE by default, and an icon-only
     button has no text baseline — so it sat 2.5px higher than its neighbours in
     the same row. Align on the middle instead. */
  vertical-align: middle;
}
.btn:hover { filter: brightness(1.06); }
.btn:active { filter: brightness(.94); transform: translateY(1px); }
/* Keyboard users need to see where they are; the ring has to work on the navy
   bar and on white, so it is drawn with an offset rather than a colour swap. */
.btn:focus-visible, .icon-btn:focus-visible, .tabs button:focus-visible,
a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--navy-2);
  outline-offset: 2px;
}
.btn[disabled], .btn:disabled {
  /* A disabled control must LOOK disabled: the gold Accept button on the terms
     gate was fully saturated and only stopped working when clicked. */
  opacity: .45;
  cursor: not-allowed;
  filter: none;
}
.btn[disabled]:hover, .btn:disabled:hover { filter: none; }
.btn.primary { background: var(--accent); color: #24292e; }
.btn.ghost { background: rgba(255,255,255,.14); color: #fff; }
.btn.outline { background: #fff; color: var(--navy); border: 1.5px solid var(--navy-2); }
.btn.wa { background: var(--wa); color: #fff; }
.btn.danger-outline { background: #fff; color: var(--warn); border: 1.5px solid var(--warn); }
.btn.small { padding: 7px 14px; font-size: 13.5px; min-height: 34px; }
/* .btn.small is 66 of the app's buttons — every row action and every table
   control. On a phone it was the one control under the 44px target. */
@media (max-width: 720px) {
  .btn.small { min-height: 44px; padding: 10px 14px; }
}

.section-label {
  /* Outranks the cards beneath it: larger, darker, and separated by a rule
     rather than by letter-spacing alone. uppercase was also mangling the
     Japanese and Indonesian labels, which have no case to speak of. */
  font-size: var(--t-xl);
  font-weight: 700;
  color: var(--navy);
  letter-spacing: .01em;
  margin: var(--s-6) 0 var(--s-3);
  padding-bottom: var(--s-2);
  border-bottom: 1px solid var(--line);
  display: flex;
  align-items: center;
  gap: var(--s-2);
}

/* ---------- wizard ---------- */
.wizard-box { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 26px 28px; box-shadow: var(--shadow); }
.wizard-q { font-size: 19px; font-weight: 700; color: var(--navy); margin-bottom: 16px; }
.wizard-opts { display: grid; gap: 10px; }
.wizard-opt {
  text-align: left; border: 1.5px solid var(--line); background: #fff; border-radius: 10px;
  padding: 13px 16px; font-size: 15px; cursor: pointer; transition: border-color .12s, background .12s;
}
.wizard-opt:hover { border-color: var(--navy-2); background: var(--info-bg); }
.wizard-back { margin-top: 14px; background: none; border: 0; color: var(--muted); cursor: pointer; font-size: 13.5px; }
.wizard-result { border-left: 4px solid var(--accent); }

/* ---------- procedure page ---------- */
.proc-header { margin-bottom: 18px; }
.proc-header .icon { font-size: 34px; }
.meta-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 10px; margin: 16px 0; }
.meta-item { background: var(--card); border: 1px solid var(--line); border-radius: 10px; padding: 10px 14px; }
.meta-item .k { font-size: 12px; color: var(--muted); font-weight: 700; text-transform: uppercase; letter-spacing: .06em; }
.meta-item .v { font-size: 14.5px; font-weight: 600; margin-top: 2px; }

.tabs { display: flex; gap: 4px; border-bottom: 2px solid var(--line); margin: 18px 0 20px; flex-wrap: wrap; }
.tabs button {
  border: 0; background: none; padding: 10px 16px; font-size: 15px; cursor: pointer;
  color: var(--muted); border-bottom: 3px solid transparent; margin-bottom: -2px; font-weight: 600;
}
.tabs button.active { color: var(--navy); border-bottom-color: var(--accent); }
/* The case-record tab is a different KIND of tab from its neighbours: they are
   the guide, it is this client's own filing. A divider before it says so without
   needing a second strip, and it carries the case's status chip so the strip
   shows where the case stands before you open it. */
.tabs button.tab-case {
  margin-left: auto; display: inline-flex; align-items: center; gap: 8px;
  border-left: 1px solid var(--line); padding-left: 18px;
}
.tabs button.tab-case .status-chip { font-weight: 600; }
@media (max-width: 720px) {
  /* the strip wraps on a phone, and an auto margin there just orphans the tab */
  .tabs button.tab-case { margin-left: 0; border-left: 0; padding-left: 16px; }
}

.callout { border-radius: 10px; padding: 13px 16px; margin: 12px 0; font-size: 14.5px; display: flex; gap: 10px; }
.callout.info { background: var(--info-bg); }
.callout.warn { background: var(--warn-bg); }
.callout.ok { background: var(--ok-bg); }
.callout .ico { flex-shrink: 0; }

.stage-block { margin-bottom: 26px; }
.stage-title {
  font-size: 17px; font-weight: 800; color: var(--navy);
  background: var(--info-bg); border-radius: 10px; padding: 10px 16px; margin-bottom: 12px;
}
.step {
  display: flex; gap: 14px; padding: 13px 14px; border: 1px solid var(--line); border-radius: 12px;
  margin-bottom: 10px; background: var(--card); align-items: flex-start;
}
.step.done { background: var(--ok-bg); border-color: #bfe6d4; }
.step { cursor: pointer; }
.step input[type=checkbox] { width: 22px; height: 22px; margin-top: 3px; accent-color: var(--ok); cursor: pointer; flex-shrink: 0; }
.step .num {
  flex-shrink: 0; width: 30px; height: 30px; border-radius: 50%; background: var(--navy); color: #fff;
  display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 14px; margin-top: 0;
}
.step.done .num { background: var(--ok); }
.step .body { flex: 1; }
.step .t { font-weight: 700; font-size: 15px; }
.step .d { font-size: 14px; color: #3a4459; margin-top: 3px; }
.step .tip { font-size: 13.5px; margin-top: 8px; background: var(--info-bg); border-radius: 8px; padding: 8px 12px; }
.step .warn-tip { font-size: 13.5px; margin-top: 8px; background: var(--warn-bg); border-radius: 8px; padding: 8px 12px; }

.doc-row {
  display: flex; gap: 12px; align-items: flex-start; padding: 11px 14px;
  border: 1px solid var(--line); border-radius: 10px; margin-bottom: 8px; background: var(--card);
}
.doc-row.done { background: var(--ok-bg); border-color: #bfe6d4; }
.doc-row input[type=checkbox] { width: 22px; height: 22px; margin-top: 3px; accent-color: var(--ok); cursor: pointer; flex-shrink: 0; }
.doc-row .n { font-weight: 600; font-size: 14.5px; }
.doc-row .note { font-size: 13px; color: var(--muted); margin-top: 2px; }
.doc-row .tpl-link { font-size: 12.5px; margin-top: 5px; display: inline-block; background: var(--info-bg); padding: 3px 10px; border-radius: 999px; }
.doc-group-title { font-weight: 700; margin: 16px 0 8px; color: var(--navy); font-size: 15px; }

.progress-wrap { display: flex; align-items: center; gap: 12px; margin: 8px 0 16px; }
.progress-bar { flex: 1; height: 10px; background: var(--line); border-radius: 999px; overflow: hidden; }
.progress-bar .fill { height: 100%; background: linear-gradient(90deg, var(--ok), #35c98f); border-radius: 999px; transition: width .3s; }
.progress-label { font-size: 13.5px; font-weight: 700; color: var(--muted); white-space: nowrap; }

.case-bar {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: var(--card); border: 1px solid var(--line); border-radius: 12px; padding: 10px 14px; margin-bottom: 14px;
}
.case-bar select, .case-bar input {
  border: 1px solid var(--line); border-radius: 8px; padding: 7px 10px; font-size: 14px; background: #fff;
}
.case-bar .lbl { font-size: 13px; font-weight: 700; color: var(--muted); }

.cost-table { width: 100%; border-collapse: collapse; margin: 10px 0; }
.cost-table th, .cost-table td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--line); font-size: 14.5px; }
.cost-table th { color: var(--muted); font-size: 12.5px; text-transform: uppercase; letter-spacing: .06em; }
.cost-table td.amount { font-weight: 700; white-space: nowrap; }

.pitfall { border-left: 4px solid var(--warn); background: var(--warn-bg); border-radius: 0 10px 10px 0; padding: 12px 16px; margin-bottom: 10px; }
.pitfall .t { font-weight: 700; }
.pitfall .b { font-size: 14px; margin-top: 2px; }

/* escalation strip */
.escalate-strip {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  background: linear-gradient(100deg, #fff8ec, #fdefd8);
  border: 1px solid #f0ddb0; border-radius: 12px; padding: 14px 18px; margin: 26px 0 8px;
}
.escalate-strip .txt { flex: 1; font-size: 14.5px; min-width: 220px; }
.escalate-strip .txt b { color: var(--navy); }

/* ---------- index catalog ---------- */
.index-card .code {
  font-size: 22px; font-weight: 800; color: var(--navy);
  background: var(--info-bg); display: inline-block; border-radius: 8px; padding: 2px 12px; margin-bottom: 8px;
}
.kv { display: grid; grid-template-columns: minmax(90px, 130px) 1fr; gap: 4px 12px; font-size: 13.5px; margin-top: 8px; }
.kv .k { color: var(--muted); font-weight: 600; }
.kv span:not(.k), .kv a { overflow-wrap: anywhere; min-width: 0; }
table.simple { width: 100%; border-collapse: collapse; font-size: 14px; }
table.simple th, table.simple td { border: 1px solid var(--line); padding: 8px 10px; text-align: left; vertical-align: top; }
table.simple th { background: var(--info-bg); }
/* A table that scrolls sideways with no visible edge just looks truncated, and
   on the workers roster the expiry columns — the whole point of the page — are
   the ones off-screen. Fade the right edge so there is something to swipe. */
.table-scroll {
  overflow-x: auto;
  background:
    linear-gradient(to right, var(--card) 30%, rgba(255,255,255,0)) left center / 24px 100% no-repeat,
    linear-gradient(to left, var(--card) 30%, rgba(255,255,255,0)) right center / 24px 100% no-repeat,
    radial-gradient(farthest-side at 0 50%, rgba(22,48,92,.16), transparent) left center / 12px 100% no-repeat,
    radial-gradient(farthest-side at 100% 50%, rgba(22,48,92,.16), transparent) right center / 12px 100% no-repeat;
  background-attachment: local, local, scroll, scroll;
}
.scroll-hint { display: none; font-size: 12px; color: var(--muted); margin: 0 0 6px; }
@media (max-width: 700px) { .scroll-hint { display: block; } }
/* row-delete buttons sat at 32x20 next to a date field */
.row-del { min-width: 34px; min-height: 34px; }
@media (max-width: 700px) { .row-del { min-width: 44px; min-height: 44px; } }

/* ---------- letters ---------- */
.letter-form label { display: block; font-size: 13px; font-weight: 700; color: var(--muted); margin: 12px 0 4px; }
.letter-form input, .letter-form textarea, .letter-form select {
  width: 100%; border: 1px solid var(--line); border-radius: 8px; padding: 9px 12px; font-size: 14.5px; font-family: inherit;
}
.letter-form textarea { min-height: 70px; }
.letter-grid { display: grid; grid-template-columns: minmax(320px, 460px) 1fr; gap: 22px; align-items: start; }
@media (max-width: 900px) { .letter-grid { grid-template-columns: 1fr; } }
.letter-preview {
  background: #fff; border: 1px solid var(--line); border-radius: 8px; padding: 34px 40px;
  font-family: "Times New Roman", serif; font-size: 14px; line-height: 1.7; min-height: 500px;
  box-shadow: var(--shadow); white-space: normal;
}
.letter-preview h4 { text-align: center; text-decoration: underline; margin: 0 0 2px; font-size: 15px; }
.letter-preview .kv-line { display: flex; }
.letter-preview .kv-line .k { width: 165px; flex-shrink: 0; }
.letter-preview .sig-row { display: flex; justify-content: space-between; margin-top: 30px; }
.letter-preview ol { margin: 6px 0; padding-left: 22px; }

/* ---------- support ---------- */
.support-hero { text-align: center; padding: 30px 20px; }
/* The hero centres its text, but neither child obeyed it, for two different
   reasons — and the result was three different left edges on one screen:
     .page-title is display:flex, and text-align does not reach a flex item, so
       the title sat hard left while everything under it was centred;
     .page-sub is capped at --measure (68ch) with no auto margins, so the BOX
       stayed left-aligned and only the text inside it centred — which is why
       the sentence started further right than the heading above it.
   These beat the base rules on specificity, so file order is not load-bearing,
   and no other page carries .page-title inside a centred container. */
.support-hero .page-title { justify-content: center; }
.support-hero .page-sub { margin-inline: auto; }
/* .support-hero .big held a 44px decorative mark that carried no information.
   The heading is the mark. Kept as a hook in case a real illustration lands. */
.support-hero .big { font-size: 44px; }
.contact-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 14px; margin-top: 18px; }

/* ---------- WA fab ---------- */
#wa-fab { position: fixed; right: 22px; bottom: 24px; z-index: 60; }
#wa-fab-btn {
  width: 58px; height: 58px; border-radius: 50%; border: 0; background: var(--wa); color: #fff;
  font-size: 26px; cursor: pointer; box-shadow: 0 4px 16px rgba(0,0,0,.25); transition: transform .12s;
}
#wa-fab-btn:hover { transform: scale(1.08); }

/* ---------- modal ---------- */
/* Above the system bars, which are fixed to the bottom at 9998. Underneath
   them, a dialog's action row was painted over on a phone — including the terms
   gate, whose only button it hid, and every confirm() replacement. The bars are
   a notice; a dialog is a question the user has to answer. */
/* THE STACKING ORDER LIVES HERE, NOT IN A style="" ATTRIBUTE.
   Raising .modal-backdrop to 10000 missed three dialogs that carried their own
   inline number — the terms gate at 190, the re-login dialog at 200 and the
   walkthrough's image zoom at 140 — because an inline declaration beats a class
   rule. The gate was the very element the change was made for: on a phone the
   fixed bottom bars went on covering its only button, and it re-asserts itself
   on every hashchange, so the app could not be used at all.
     9997-9999  the fixed bottom bars (update toast, sysbar, rejected)
     10000      an ordinary dialog
     10001      the walkthrough, which takes the whole screen
     10002      the terms gate: it outranks a dialog because nothing may be
                answered before it
     10003      the re-login dialog: the session is gone, so it outranks the gate
     10004      the image zoom, which opens from inside the walkthrough
   Add a class here rather than a number over there. */
.modal-backdrop {
  position: fixed; inset: 0; background: rgba(15, 25, 45, .55); z-index: 10000;
  display: flex; align-items: center; justify-content: center; padding: 20px;
}
.modal {
  background: #fff; border-radius: 16px; max-width: 640px; width: 100%; max-height: 88vh; overflow-y: auto;
  padding: 26px 28px; box-shadow: 0 12px 40px rgba(0,0,0,.3);
}
.modal h3 { margin-top: 0; color: var(--navy); }
/* Status chips used to be built inline as color + the same hue at 9% alpha,
   which lands around 3.2:1 — below AA for 12px text. The text colour is darkened
   here instead of at each call site. */
.status-chip { font-weight: 700; font-size: 12px; border-radius: 999px; padding: 3px 10px; display: inline-block; }
.status-chip.s-approved { background: #eaf6f1; color: var(--ok-text); }
.status-chip.s-submitted { background: #e7eefc; color: #17458f; }
.status-chip.s-preparing { background: #f1f0ec; color: #55503f; }
.status-chip.s-rejected { background: #fbeceb; color: #a3271b; }
.status-chip.s-paid { background: #f1ebfa; color: #56218c; }
.status-chip.s-review { background: #fbf1e0; color: #7a4300; }
.status-chip.s-returned { background: #fbeceb; color: #a3271b; }
/* A consent gate must never push its own Accept button below the fold. On a
   360x640 phone the terms modal was 638px of content inside a 563px box, so the
   checkbox and the only button were off-screen with nothing to say so. As a
   flex column the heading, checkbox and actions stay put and only the text
   scrolls. */
.modal.gate-flex { display: flex; flex-direction: column; overflow: hidden; }
.modal.gate-flex > .gate-scroll {
  flex: 1 1 auto; min-height: 84px; overflow-y: auto; -webkit-overflow-scrolling: touch;
  border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px;
  background: var(--bg); font-size: 13px; line-height: 1.65;
}
.modal.gate-flex > .gate-scroll:focus-visible { outline: 2px solid var(--navy); outline-offset: 2px; }
.modal textarea { width: 100%; min-height: 160px; border: 1px solid var(--line); border-radius: 8px; padding: 10px; font-size: 13.5px; font-family: inherit; }
.modal .modal-actions { display: flex; gap: 10px; margin-top: 16px; flex-wrap: wrap; }
.modal label { display: block; font-size: 13px; font-weight: 700; color: var(--muted); margin: 10px 0 4px; }
.modal input, .modal select { width: 100%; border: 1px solid var(--line); border-radius: 8px; padding: 9px 12px; font-size: 14.5px; }
/* ...but a checkbox is not a text field. The unqualified rule above stretched the
   terms-of-use consent box to the full width of the dialog with a text-input
   border, so it did not read as something to tick. */
.modal input[type="checkbox"], .modal input[type="radio"] {
  width: 18px; height: 18px; padding: 0; border-radius: 4px; flex: 0 0 auto;
}

/* The "you are viewing another company's data" band. It existed in the DOM with
   no rule but the print-hide, so the single warning that stops an FPI admin
   typing into the wrong client's account looked like an ordinary paragraph. */
.tenant-banner {
  background: #8a4b00; color: #fff; font-weight: 700; font-size: 13.5px;
  padding: 8px 16px; text-align: center; letter-spacing: .01em;
}
.tenant-banner strong { text-decoration: underline; }

/* ---------- settings ---------- */
.settings-form { max-width: 560px; }
.settings-form label { display: block; font-size: 13px; font-weight: 700; color: var(--muted); margin: 14px 0 4px; }
.settings-form input, .settings-form select { width: 100%; border: 1px solid var(--line); border-radius: 8px; padding: 9px 12px; font-size: 14.5px; }
/* --ok is the fill colour for badges and checkboxes; as TEXT on the page
   background it is 3.32:1, below the 4.5:1 AA floor. --ok-text exists for this. */
.save-note { color: var(--ok-text); font-size: 14px; margin-left: 10px; }

/* ---------- autosave state ----------
   Nothing in this product has a Save button; every field commits on change. That
   is right for a checklist somebody ticks forty times, and wrong to leave
   unexplained — a user who types an amount and sees no button and no confirmation
   cannot tell whether their work is safe. Three states, in the place they typed. */
.save-state {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: var(--s-3); padding: 5px 10px; border-radius: var(--r-pill);
  font-size: var(--t-xs); font-weight: 600;
  /* --muted on this grey measured 4.39:1 — under the 4.5:1 floor for text this
     size. The resting state is the one that says "your work is saved
     automatically", so it is the one that has to be readable. */
  background: #eef1f6; color: #52607a;
  transition: background .15s, color .15s;
}
.save-state .vh-i { width: 1.15em; height: 1.15em; }
.save-state[data-state="saving"] { background: var(--info-bg); color: var(--navy-2); }
.save-state[data-state="saved"]  { background: var(--ok-bg);   color: var(--ok-text); }
.save-state[data-state="error"]  { background: var(--warn-bg); color: #a8321c; }
/* The confirmation is transient information; on paper it is noise. */
@media print { .save-state { display: none; } }

/* ---------- login & session ---------- */
.login-wrap { display: flex; justify-content: center; padding: 60px 16px; }
.login-card {
  background: var(--card); border: 1px solid var(--line); border-radius: 18px;
  box-shadow: 0 8px 30px rgba(22,48,92,.15); padding: 34px 36px; width: 100%; max-width: 400px;
}
.login-card label { display: block; font-size: 13px; font-weight: 700; color: var(--muted); margin: 14px 0 4px; }
.login-card input { width: 100%; border: 1px solid var(--line); border-radius: 10px; padding: 11px 14px; font-size: 15px; }
.login-card .btn { margin-top: 6px; }
#user-chip { display: flex; align-items: center; gap: 7px; }
#user-chip .chip-company, #user-chip .chip-user {
  font-size: 12px; color: #d7e0f2; background: rgba(255,255,255,.12); border-radius: 999px; padding: 4px 11px;
  max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#user-chip select {
  font-size: 12px; background: rgba(255,255,255,.14); color: #fff; border: 0; border-radius: 999px; padding: 4px 8px; max-width: 170px;
}
#user-chip select option { color: #1c2434; }
/* Log out — it used to be a bare "⎋" (the ESC-key glyph), which reads as
   "logout" to approximately nobody, in a 29x24px tap target with only a
   tooltip for a name. Now: a named pill with a sign-out mark, neutral at rest
   so it does not compete with the nav, and unmistakably "leaving" on hover. */
#user-chip .chip-logout {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid rgba(255,255,255,.22);
  background: rgba(255,255,255,.10);
  color: #d7e0f2;                      /* 9.8:1 on --navy */
  border-radius: 999px; padding: 5px 12px 5px 10px;
  cursor: pointer; font-size: 12.5px; font-weight: 600; line-height: 1;
  white-space: nowrap;
  transition: background .14s ease, border-color .14s ease, color .14s ease;
}
#user-chip .chip-logout svg { flex: none; opacity: .9; }
#user-chip .chip-logout:hover,
#user-chip .chip-logout:focus-visible {
  background: rgba(214,76,52,.30);
  border-color: rgba(255,176,160,.75);
  color: #ffe3dc;                      /* 8.6:1 on the blended hover ground */
}
#user-chip .chip-logout:hover svg { opacity: 1; }
#user-chip .chip-logout:focus-visible { outline: 2px solid #ffd9d2; outline-offset: 2px; }
#user-chip .chip-logout:active { transform: translateY(1px); }
@media (prefers-reduced-motion: reduce) {
  #user-chip .chip-logout { transition: none; }
  #user-chip .chip-logout:active { transform: none; }
}

/* ---------- CMS content editor ---------- */
.cms-tabs { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; margin: 12px 0 16px; }
.cms-tabs button {
  border: 1px solid var(--line); background: #fff; border-radius: 999px; padding: 7px 14px;
  font-size: 13.5px; cursor: pointer; font-weight: 600; color: var(--muted);
}
.cms-tabs button.active { background: var(--navy); color: #fff; border-color: var(--navy); }
.cms-toolbar {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  background: var(--card); border: 1px solid var(--line); border-radius: 10px; padding: 10px 14px; margin: 12px 0;
  /* The desktop header is TWO rows above 980px (see the #mainnav rule), so a
     62px offset painted the Save/Publish/Revert bar underneath it. */
  position: sticky; top: 62px; z-index: 20;
}
@media (min-width: 981px) { .cms-toolbar { top: 108px; } }
.cms-form .cms-field { margin-bottom: 12px; }
.cms-form .cms-field-label {
  font-size: 12.5px; font-weight: 800; color: var(--navy); text-transform: none; margin-bottom: 3px;
  font-family: Consolas, monospace;
}
.cms-form input, .cms-form textarea, .cms-form select {
  width: 100%; border: 1px solid var(--line); border-radius: 8px; padding: 7px 10px; font-size: 13.5px; font-family: inherit;
}
.cms-form input:disabled { background: #f0f2f7; color: var(--muted); }
.cms-tri { display: grid; gap: 5px; }
.cms-lang { display: flex; gap: 6px; align-items: flex-start; }
.cms-lang-tag {
  flex-shrink: 0; width: 30px; text-align: center; font-size: 10.5px; font-weight: 800; color: #fff;
  background: var(--navy-2); border-radius: 5px; padding: 3px 0; margin-top: 5px;
}
.cms-object { border-left: 3px solid var(--line); padding-left: 12px; }
.cms-array-item { border: 1px solid var(--line); border-radius: 10px; padding: 10px 12px; margin-bottom: 8px; background: #fbfcfe; }
.cms-array-head { display: flex; gap: 6px; align-items: center; margin-bottom: 6px; }
.cms-array-no { font-weight: 800; font-size: 12px; color: var(--muted); }
/* These were 29x21 — under the 24x24 WCAG 2.5.8 (AA) floor — and two of them
   (the journey ✕ and the CMS row ✕) DELETE something. On a phone a mis-tap on a
   21px-tall delete control is a matter of when, not if, so they get a full 44px
   touch target there. */
.cms-mini {
  border: 1px solid var(--line); background: #fff; border-radius: 6px; padding: 2px 9px; cursor: pointer; font-size: 12px;
  min-width: 30px; min-height: 28px;
}
@media (max-width: 700px) { .cms-mini { min-width: 44px; min-height: 44px; font-size: 15px; } }
.cms-mini:disabled { opacity: .3; cursor: default; }
.cms-mini.cms-danger { color: #c0392b; border-color: #e5b3ab; }
.cms-proc-card { padding: 12px 14px; }

/* ---------- footer ---------- */
#footer { background: #0f2244; color: #9fb0cd; font-size: 12.5px; }
.footer-inner { max-width: 1120px; margin: 0 auto; padding: 18px 20px; display: flex; gap: 20px; justify-content: space-between; flex-wrap: wrap; }
.footer-brand { font-weight: 700; color: #cdd9ef; }

/* ---------- print ---------- */
@media print {
  #topbar, #footer, #wa-fab, .no-print, .tenant-banner, .scroll-hint { display: none !important; }
  /* A scrolling container CLIPS in print: the compliance pack handed to an
     inspector was losing its right-hand columns entirely. */
  .table-scroll { overflow: visible !important; background: none !important; }
  table { width: 100% !important; table-layout: fixed; font-size: 10pt; }
  th, td { word-wrap: break-word; overflow-wrap: anywhere; }
  /* keep rows and their headings together across page breaks */
  tr, .doc-row, .step, .card { break-inside: avoid; page-break-inside: avoid; }
  h1, h2, h3, .page-title, .section-label { break-after: avoid; page-break-after: avoid; }
  #view { max-width: none; padding: 0; }
  body { background: #fff; }
  /* browsers strip backgrounds when printing — keep hero/emergency text readable */
  .hero, .emergency-hero { background: #fff !important; color: #000 !important; border: 1px solid #000; }
  .hero p, .emergency-hero p, .hero h1, .emergency-hero h1 { color: #000 !important; }
  .btn { background: #fff !important; color: #000 !important; border: 1px solid #000 !important; }
  .badge { border: 1px solid #999; }
  .wt-backdrop, .modal-backdrop { display: none !important; }
}
/* ---------- compact / mobile navigation ---------- */
#nav-toggle {
  display: none; border: 0; background: rgba(255,255,255,.14); color: #fff;
  font-size: 20px; border-radius: 8px; padding: 6px 12px; cursor: pointer;
}
@media (max-width: 980px) {
  #topbar { gap: 10px; }
  /* the open menu is a column inside a sticky bar: without a bound it grows
     past the viewport and its last items cannot be reached at all */
  #mainnav { max-height: calc(100vh - 116px); overflow-y: auto; -webkit-overflow-scrolling: touch; }
  /* comfortable touch targets (44px) for the controls crowded into the bar */
  #nav-toggle, .icon-btn, .sos-link, #user-chip .chip-logout, .lang-switch button {
    min-height: 44px; display: inline-flex; align-items: center; justify-content: center;
  }
  /* the bar is tight on a phone: keep the mark, drop the word — the button
     still carries its name via aria-label and title */
  #user-chip .chip-logout { padding: 5px 11px; min-width: 44px; }
  #user-chip .chip-logout-text { display: none; }
  /* 44px, not 40: this is the app's most-used control and the WCAG target the
     rest of the phone layout already meets. */
  .btn.small { min-height: 44px; }
  .topbar-right { flex-wrap: wrap; justify-content: flex-end; }
  #nav-toggle { display: block; }
  #mainnav {
    display: none; order: 10; flex-basis: 100%; flex-direction: column; gap: 2px;
    padding: 8px 0 4px; border-top: 1px solid rgba(255,255,255,.15); margin-top: 6px;
  }
  body.nav-open #mainnav { display: flex; }
  #mainnav a { padding: 11px 12px; font-size: 15px; }
  .topbar-right { margin-left: auto; }
  #user-chip .chip-company, #user-chip .chip-user { max-width: 90px; }
  #user-chip select { max-width: 110px; }
  /* icon-only SOS on small screens — the mark carries the meaning alone, so it
     grows, and the pill keeps a 44px hit area (the emergency link is the worst
     one to make someone aim at). Its name stays on aria-label and title. */
  .sos-link span { display: none; }
  .sos-link { min-width: 44px; padding: 5px; gap: 0; }
  /* the matching icon size lives in the icon-system section — the base
     .sos-link .vh-i rule is declared LATER in this file and a media query adds
     no specificity, so an override here would silently lose the cascade */
  .lang-switch button { padding: 6px 8px; font-size: 12px; }
}
@media (max-width: 700px) {
  /* The sticky bar was ~163px tall — a fifth of a 812px phone — on every page. */
  #topbar { padding: 6px 14px; gap: 8px; row-gap: 6px; }
  .brand { font-size: 16px; }
  .brand-mark { font-size: 21px; }
  #user-chip .chip-company, #user-chip .chip-user { max-width: 78px; font-size: 11px; padding: 3px 8px; }
  .hero { padding: 24px 20px; }
  .hero h1 { font-size: 23px; }
  #view { padding: 18px 14px 120px; } /* clear of the 58px WA fab */
  .letter-preview { padding: 20px 16px; }
  /* prevent iOS Safari focus auto-zoom (needs ≥16px inputs) */
  input, select, textarea { font-size: 16px !important; }
  #wa-fab { right: 14px; bottom: 16px; }
  #wa-fab-btn { width: 52px; height: 52px; font-size: 23px; }
}

/* inline field validation — the message belongs next to the field that caused it */
.field-err { color: #a8321c; font-size: 12.5px; font-weight: 600; margin-top: 4px; min-height: 1px; }
[aria-invalid="true"] { border-color: #a8321c !important; outline: 2px solid rgba(168,50,28,.18); }

/* ---------- icon system ----------
   One stroke set on a 24x24 grid (app/js/icons.js). Icons inherit the colour of
   the text they sit in — which is the whole reason they replaced the emoji — so
   nothing here may set a colour. Size follows the surrounding font-size unless
   a call site asks for a pixel size. */
/* The size MUST be declared here, not left to the caller. VH_ICON() writes
   width/height into an inline style, so every scripted icon carried its own
   size and this rule never needed one — until a hand-written <svg class="vh-i">
   went into index.html with no style attribute and no scoped rule to catch it.
   An <svg> with no intrinsic size falls back to the replaced-element default
   (300x150), which is how the SOS pill grew a phone the height of the topbar.
   1.05em matches what VH_ICON emits; inline styles and the scoped rules below
   both outrank this, so nothing that already sized correctly moves. */
.vh-i { display: inline-block; flex: none; vertical-align: -.16em; width: 1.05em; height: 1.05em; }
/* An icon-only control still needs a real hit area on a phone. */
.icon-btn .vh-i { width: 1.15em; height: 1.15em; }
.sos-link .vh-i { width: 1.25em; height: 1.25em; }
/* At 980px the pill loses its label (same breakpoint that hides .sos-link span),
   so the mark carries the meaning alone and grows. This sits here, AFTER the
   rule it overrides, deliberately: a media query adds no specificity, so up in
   the responsive section it would have lost to the line above. */
@media (max-width: 980px) { .sos-link .vh-i { width: 1.5em; height: 1.5em; } }
.brand-mark .vh-i { color: var(--accent); }
#wa-fab-btn .vh-i { width: 1.5em; height: 1.5em; }
/* In print the stroke has to be dark enough to survive a mono laser printer. */
@media print { .vh-i { stroke-width: 1.9; } }

/* ---------- identifiers ----------
   Passport numbers, KITAS numbers, permit reference numbers and dates: strings
   that are compared character by character, by a person who did not type them.
   They were rendering as the smallest and palest text on the page, in a
   proportional face where 0/O and 1/l are ambiguous. */
.ref-value, .doc-row .n code, td.ref, .num {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1, "zero" 1;
  letter-spacing: .02em;
  color: var(--ink);
}
.ref-value { font-weight: 600; }
/* Any table column of figures lines up. */
table .amount, table td.num { font-variant-numeric: tabular-nums; }

/* ---------- measure ----------
   Running prose gets a readable line length; tables and rows keep the full
   width, which is what they are for. */
.desc, .callout > div, .page-sub, p.lead { max-width: var(--measure); }
/* A short stub on the last line — 「できます。」 alone under two full lines — reads
   as a mistake. `pretty` asks the browser to pull a word or two down from the
   line above rather than filling each line to the edge and leaving the
   remainder; unlike `balance` it does not re-lay the whole block, so it is safe
   on prose of any length. Measured across 16 routes: 6 such stubs before, 0
   after. Ignored where unsupported, so the fallback is today's wrapping. */
.desc, .page-sub, .note, .callout > div, p.lead, .tip-item .td { text-wrap: pretty; }

/* A card whose text is centred. The class exists so the auto margins below can
   be attached to something: .desc and .page-sub are capped at --measure, and a
   capped block with no auto margins sits at the LEFT of its container while only
   the text inside it centres — which is why the plans page's closing paragraph
   read as ragged and off-centre under a centred heading. Same failure the
   support hero had; this is the reusable version. */
.card.center { text-align: center; }
.card.center > .desc,
.card.center > .page-sub,
.card.center > p { margin-inline: auto; }

/* ---------- plans & pricing ----------
   Three cards side by side, equal height whatever the copy does, and a
   comparison table underneath. The client's OWN plan is marked in both, because
   the first question anyone brings to a pricing page they already pay for is
   "which one am I on?". */
.plan-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--s-3); margin-bottom: var(--s-5);
}
/* The card IS the control — see renderPlans. It is an <a>, so it needs its own
   text colour and hover state back; inheriting the link blue would repaint the
   price and the plan name. */
.plan-card {
  position: relative; background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: var(--s-5) var(--s-4) var(--s-4);
  box-shadow: var(--shadow); display: flex; flex-direction: column;
  color: inherit; text-decoration: none;
  transition: transform .12s ease, box-shadow .12s ease, border-color .12s ease;
}
.plan-card:hover, .plan-card:focus-visible {
  border-color: var(--navy-2); box-shadow: 0 6px 18px rgba(22, 48, 92, .16);
  transform: translateY(-2px);
}
.plan-card:focus-visible { outline: 2px solid var(--navy-2); outline-offset: 2px; }
.plan-card .plan-cta {
  margin-top: auto; padding-top: var(--s-3);
  display: inline-flex; align-items: center; gap: var(--s-1);
  font-size: var(--t-sm); font-weight: 700; color: var(--navy-2);
}
.plan-card.featured .plan-cta { color: var(--gold-ink, #8a6410); }
@media (prefers-reduced-motion: reduce) {
  .plan-card { transition: none; }
  .plan-card:hover, .plan-card:focus-visible { transform: none; }
}
.plan-card.featured { border-color: var(--accent); }

.plan-card h3 { margin: 0 0 2px; font-size: var(--t-lg); color: var(--navy); }
.plan-card .plan-for { margin: 0 0 var(--s-3); font-size: var(--t-sm); color: var(--muted); }
.plan-card .plan-price { margin: 0; font-size: var(--t-xl); font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }
.plan-card .plan-price .unit { font-size: var(--t-sm); font-weight: 600; color: var(--muted); }
/* The annual figure is the one that can actually be bought, so it is stated in
   full rather than left for the reader to multiply. */
.plan-card .plan-annual { margin: var(--s-1) 0 0; font-size: var(--t-sm); color: var(--muted); font-variant-numeric: tabular-nums; }
/* The answer to "which plan am I on", stated in words above the cards rather
   than left to a border colour. */
.plan-status {
  display: flex; gap: var(--s-2); align-items: center;
  background: var(--info-bg); border: 1px solid var(--navy-2);
  border-radius: var(--r-md); padding: var(--s-3) var(--s-4);
  margin-bottom: var(--s-4); font-size: var(--t-sm); color: var(--ink);
}
.plan-status .vh-i { flex: none; color: var(--navy-2); }
.plan-status b { color: var(--navy-2); }
.plan-status.admin { background: #eef1f6; border-color: var(--line); color: var(--muted); }
.plan-status.admin b { color: var(--ink); }
/* ...and on the card itself, unmistakably. A 2px border was the whole signal. */
.plan-card.current {
  border-color: var(--navy-2); border-width: 2px;
  box-shadow: 0 0 0 4px rgba(31, 66, 135, .12), var(--shadow);
}
.plan-flag {
  position: absolute; top: -10px; left: var(--s-4);
  background: var(--navy-2); color: #fff; border-radius: var(--r-pill);
  padding: 2px 10px; font-size: var(--t-xs); font-weight: 700;
}
.plan-flag.alt { background: var(--accent); color: #1c2434; }
.plan-table td, .plan-table th { vertical-align: middle; }
/* Which column is which plan, thirty-seven rows down.
   NOT position:sticky. The table has to scroll sideways on a phone, and a box
   with overflow-x:auto computes overflow-y to hidden even when told clip — so it
   becomes the scroll container, and a sticky header pins to a box that never
   scrolls vertically. Measured: the header left the viewport exactly as before.
   The topbar is 160px tall and would cover it anyway.
   So repeat the plan names at the head of every group instead. It needs no
   coordination with the topbar, works at every width, and survives print. */
.plan-table .plan-rehead td {
  background: var(--bg); color: var(--navy); font-weight: 700;
  font-size: var(--t-xs); text-align: center;
  border-top: 2px solid var(--line); padding-top: var(--s-2); padding-bottom: var(--s-2);
}
.plan-table .plan-rehead td.grp, .plan-table .plan-rehead td.lbl { background: var(--bg); }
.plan-table .plan-rehead td.me { color: var(--navy-2); background: var(--info-bg); }
.plan-compare-hint { margin: calc(var(--s-2) * -1) 0 var(--s-3); font-size: var(--t-xs); }
.plan-contact { margin: var(--s-5) 0; }
.plan-table th.me { color: var(--navy-2); }
.plan-table td.off { color: var(--muted); }
.plan-notes { font-size: var(--t-xs); color: var(--muted); margin-top: var(--s-3); }

/* A feature the current plan does not include: shown, explained, never a dead
   control the user pokes at wondering why nothing happens. */
.plan-locked {
  display: flex; gap: var(--s-2); align-items: flex-start;
  background: #eef1f6; border: 1px dashed var(--line); border-radius: var(--r-md);
  padding: var(--s-3) var(--s-4); font-size: var(--t-sm); color: #52607a;
}
.plan-locked .vh-i { flex: none; margin-top: 2px; }
.plan-locked a { font-weight: 700; white-space: nowrap; }

/* Included / not included, as marks. Deliberately the app's own stroke icons and
   not the emoji a reference design would use: emoji are drawn by the OS, so the
   same table looks different on every client's machine; they cannot take a
   colour; and they print as grey blobs, which is the fault that got emoji
   removed from this product to begin with. Each mark carries an aria-label, so
   a screen reader hears "included" rather than nothing. */
.plan-table .mkcell { text-align: center; vertical-align: middle; }
.plan-table .mk { display: inline-flex; align-items: center; justify-content: center; }
.plan-table .mk .vh-i { width: 1.25em; height: 1.25em; stroke-width: 2.4; }
.plan-table .mk.yes { color: var(--ok-text); }
.plan-table .mk.no  { color: #c0392b; }
/* A limit ("1件まで") is information, not a mark — it stays as words. */
.plan-table .mk.txt { font-size: var(--t-sm); font-weight: 600; color: var(--ink); }
.plan-table .mk-note { font-size: 10px; color: var(--muted); margin-left: 1px; }
/* The category column labels a block of rows rather than repeating per line. */
.plan-table th.grp {
  text-align: left; vertical-align: middle; white-space: nowrap;
  background: #f2f5fa; color: var(--navy); font-size: var(--t-sm);
  border-right: 1px solid var(--line);
}

/* ---------- system bar ----------
   The app's data-loss and update messages: a colleague's edit overwrote yours,
   the server refused a save, a new version is ready. They were four separate
   hand-rolled implementations in four different browns with three different
   close buttons — so the one class of message a user MUST recognise instantly
   looked like three unrelated things. One component, one geometry, one close
   button; only the accent changes with severity. */
.sysbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 9998;
  display: flex; gap: var(--s-3); align-items: flex-start;
  padding: var(--s-3) var(--s-4);
  font-size: var(--t-sm); line-height: 1.5;
  color: #fff; background: var(--sysbar-bg, #8a4b00);
  box-shadow: 0 -2px 12px rgba(0,0,0,.25);
}
.sysbar > .msg { flex: 1; display: flex; gap: var(--s-2); align-items: flex-start; }
.sysbar .btn { flex: none; }
.sysbar .btn.bar-action { background: #fff; color: var(--sysbar-bg, #8a4b00); border: 0; }
.sysbar .btn.bar-close {
  background: transparent; color: #fff; border: 1px solid rgba(255,255,255,.6);
  /* Height comes from .btn.small like every other button; this rule used to pin
     36px and so stood 2px taller than the .bar-action beside it in the same bar.
     min-width stays: it is icon-only and still needs a real hit area, and the
     720px breakpoint lifts every .btn.small to 44px. */
  min-width: 44px;
}
.sysbar.warn   { --sysbar-bg: #8a4b00; }   /* a colleague's edit landed first */
.sysbar.danger { --sysbar-bg: #7a1f1f; }   /* the server refused a save        */
.sysbar.info   { --sysbar-bg: #12315e; }   /* a new version is ready           */
@media (max-width: 600px) {
  .sysbar { flex-wrap: wrap; }
  .sysbar > .msg { flex-basis: 100%; }
}

/* ---------- button variants ----------
   .btn.outline is the most-used control in the app and its only hover was
   brightness(1.06) on #fff — which is #fff. It had no hover state at all. */
.btn.outline:hover { background: var(--info-bg); border-color: var(--navy); filter: none; }
.btn.outline:active { background: #e3ebfa; }
.btn.danger-outline:hover { background: var(--warn-bg); filter: none; }
/* The variant 11 of .btn.ghost's 13 call sites were hand-rolling inline: a
   quiet secondary button on a LIGHT ground. .btn.ghost itself is the one for a
   dark ground and keeps its meaning. */
.btn.subtle {
  background: #eef1f6; color: var(--ink); border: 1px solid var(--line);
}
.btn.subtle:hover { background: #e4e9f1; filter: none; }

/* Three system bars can be on screen at once (a colleague's edit, a refused
   save, a new version). layoutBottomBars() stacks the two in app.js; the update
   toast is owned by pwa.js and simply sits above them. */
#vh-update-toast.sysbar { z-index: 9997; bottom: 0; }

/* ---------- tab strip ----------
   The active tab was marked with a bottom border on the button while the strip
   itself wraps to two or three rows on a phone — so the marker sat under a
   button in the middle of the block and read as a divider, not as "you are
   here". A filled chip stays attached to its own label however the strip wraps. */
.tabs { display: flex; flex-wrap: wrap; gap: var(--s-1); border-bottom: 1px solid var(--line); padding-bottom: var(--s-1); }
.tabs button {
  border: 0; background: transparent; cursor: pointer;
  padding: 9px 14px; border-radius: var(--r-sm) var(--r-sm) 0 0;
  font-size: var(--t-sm); font-weight: 600; color: var(--muted);
  min-height: 44px;
}
.tabs button:hover { background: var(--info-bg); color: var(--navy); }
.tabs button.active { background: var(--navy); color: #fff; border-bottom: 0; }

/* ---------- card grids ----------
   .cols-2 and .cols-3 both used auto-fit with a minmax floor small enough that
   BOTH resolved to three columns at the app's content width, so asking for two
   columns did nothing and four cards broke 3 + 1. Ask for the count. */
.grid.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
@media (max-width: 900px) { .grid.cols-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 620px) { .grid.cols-2, .grid.cols-3 { grid-template-columns: 1fr; } }

/* The filing record now sits below the checklist; give it a rule so it reads as
   a separate section rather than as more checklist. */
#case-panel { margin-top: var(--s-6); }

/* ---------- critical rule ----------
   Reserved for rules that CANCEL a filing: the client has paid, the work is
   done, and one wrong move voids it. There are only a handful in the whole
   product, and they must not look like the ordinary warn callout that appears
   several times per guide. Solid ground, a heavy rule, its own label. */
.callout.critical {
  background: #fdf2ee;
  border: 1.5px solid #d9856a;
  border-left: 6px solid #a8321c;
  border-radius: var(--r-md);
  padding: var(--s-4) var(--s-4) var(--s-4) var(--s-3);
  margin: var(--s-4) 0;
  gap: var(--s-3);
  box-shadow: 0 2px 10px rgba(168, 50, 28, .10);
}
.callout.critical .ico { color: #a8321c; }
.callout.critical .ico .vh-i { width: 1.5em; height: 1.5em; }
.callout.critical .crit-label {
  display: inline-block;
  background: #a8321c; color: #fff;
  font-size: var(--t-xs); font-weight: 700; letter-spacing: .04em;
  border-radius: var(--r-sm);
  padding: 2px 9px;
  margin-bottom: var(--s-2);
}
.callout.critical .crit-title {
  display: block;
  font-size: var(--t-lg); font-weight: 700; color: #8a2716;
  margin-bottom: var(--s-1);
  line-height: 1.45;
}
.callout.critical .crit-body { color: #4a2318; }
.callout.critical .crit-body p { margin: 0 0 var(--s-2); }
.callout.critical .crit-body p:last-child { margin-bottom: 0; }
/* It has to survive the printer too — this is the rule an officer or an auditor
   may be shown as the reason a filing was scheduled the way it was. */
@media print {
  .callout.critical { background: #fff; border: 1.5pt solid #a8321c; box-shadow: none; }
  .callout.critical .crit-label { background: #fff; color: #a8321c; border: 1pt solid #a8321c; }
}

/* The critical callout stays compact: the rule, then a disclosure. */
.callout.critical { padding: var(--s-3) var(--s-4) var(--s-3) var(--s-3); }
.callout.critical .crit-title { font-size: var(--t-md); margin-bottom: var(--s-1); }
.callout.critical .crit-body p { line-height: 1.6; }
.crit-more { margin-top: var(--s-2); }
.crit-more > summary {
  cursor: pointer; list-style: none;
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--t-sm); font-weight: 600; color: #8a2716;
  padding: 4px 0; min-height: 32px;
}
.crit-more > summary::-webkit-details-marker { display: none; }
.crit-more > summary::before {
  content: ""; width: 0; height: 0;
  border-left: 5px solid currentColor; border-top: 4px solid transparent; border-bottom: 4px solid transparent;
  transition: transform .15s;
}
.crit-more[open] > summary::before { transform: rotate(90deg); }
.crit-more > summary:hover { text-decoration: underline; }
.crit-cite { font-size: var(--t-xs); color: #6b4436; margin-top: var(--s-2) !important; }
/* On paper the reasoning and the citation are the point. The <details> itself
   is opened by the beforeprint handler in app.js — author CSS cannot reveal a
   closed one — so all this rule has to do is drop the now-pointless twisty. */
@media print {
  .crit-more > summary { display: none; }
}
