/**
 * 利用者向け画面
 *
 * スマホを主に想定している。
 * フォームは Material Design の outlined text field に寄せた作り。
 *
 * 外部のCSSフレームワークは使わない。
 * Material のライブラリを入れると、必要な数個のために
 * 数百KBを読ませることになるため。
 */

:root {
    /* Material のロール名に寄せた命名。色を変えるならここだけ触る */
    --kb-primary:        #1a5fb4;
    --kb-primary-hover:  #164e94;
    --kb-on-primary:     #ffffff;
    --kb-surface:        #ffffff;
    --kb-surface-variant:#f4f4f6;
    --kb-on-surface:     #1c1b1f;
    --kb-on-surface-var: #49454f;
    --kb-outline:        #79747e;
    --kb-outline-variant:#cac4d0;
    --kb-error:          #b3261e;
    --kb-success:        #1a7f37;

    --kb-radius:         4px;
    --kb-gutter:         10px;
}

/* ============================================================
   全体
   ============================================================ */

/**
 * box-sizing は全体に効かせる
 *
 * 要素ごとに指定していると、あとから足した要素で
 * width:100% + padding のはみ出しが起きる。
 */
*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    /*
     * iOS Safari で横スクロールが出ないようにする最後の砦。
     * ただし原因は個別に潰してある（overflow で隠すと
     * position: sticky が効かなくなるなどの副作用があるため、
     * これに頼らない作りにしている）。
     */
    max-width: 100%;
}

body {
    max-width: 100%;
    /*
     * 長いURLや連続した英数字で横に伸びるのを防ぐ。
     * 予約コードや受取コードは短いが、URLを出す箇所がある。
     */
    overflow-wrap: break-word;
    word-break: normal;
    margin: 0;
    color: var(--kb-on-surface);
    background: var(--kb-surface);
    font-family:
        -apple-system, BlinkMacSystemFont, "Segoe UI",
        "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Noto Sans JP",
        Meiryo, sans-serif;
    line-height: 1.7;
    -webkit-text-size-adjust: 100%;
}

/**
 * 両端の余白
 *
 * どの画面幅でも必ず10px空ける。
 * 広い画面では中央に寄せるが、余白の指定は残す。
 */
main {
    box-sizing: border-box;
    width: 100%;
    max-width: 640px;
    margin: 0 auto;
    padding: 24px var(--kb-gutter) 64px;
}

h1 {
    margin: 0 0 24px;
    font-size: 1.5rem;
    line-height: 1.4;
}

h2 {
    margin: 32px 0 16px;
    font-size: 1.125rem;
}

h3 {
    margin: 24px 0 12px;
    font-size: 1rem;
}

a { color: var(--kb-primary); }

/* ============================================================
   フォーム
   ============================================================ */

form { margin: 0; }

fieldset {
    margin: 0 0 8px;
    padding: 0;
    border: 0;
    /*
     * ブラウザの既定スタイルは fieldset に min-inline-size: min-content を当てる。
     * 中に長い option を持つ select があると、その min-content 幅に合わせて
     * fieldset が画面幅を超えて広がる。width や box-sizing では縮まない。
     * iOS Safari で横スクロールが出る原因のひとつ。
     */
    min-width: 0;
}

legend {
    display: block;
    width: 100%;
    margin: 24px 0 16px;
    padding: 0;
    font-size: 1.0625rem;
    font-weight: 600;
    color: var(--kb-on-surface);
}

fieldset:first-of-type legend { margin-top: 0; }

/**
 * outlined text field
 *
 * ラベルを input の後ろに置いて、兄弟セレクタで浮かせる。
 * placeholder=" " を入れておくのが要点で、
 * :not(:placeholder-shown) で「入力があるか」を判定できる。
 */
.kb-field {
    position: relative;
    margin: 0 0 24px;
}

.kb-field > input,
.kb-field > select,
.kb-field > textarea {
    box-sizing: border-box;
    width: 100%;
    /*
     * iOS Safari の date / time 入力は内部に独自の構造を持ち、
     * その最小幅に引っ張られて縮まないことがある。
     */
    min-width: 0;
    max-width: 100%;
    /* 高さはタップしやすい56px。Material の推奨に合わせている */
    min-height: 56px;
    padding: 16px 14px;
    /* 16px 未満だと iOS Safari が勝手にズームする */
    font-size: 16px;
    font-family: inherit;
    line-height: 1.4;
    color: var(--kb-on-surface);
    background: var(--kb-surface);
    border: 1px solid var(--kb-outline-variant);
    border-radius: var(--kb-radius);
    outline: none;
    transition: border-color .15s, box-shadow .15s;
    appearance: none;
}

.kb-field > textarea {
    min-height: 120px;
    resize: vertical;
}

/*
 * select は中の option の幅で押し広げられることがある。
 * 明示的に上限を切る。長い施設名は途中で切れるが、
 * 開いたときの一覧では全文が見えるので実用上困らない。
 */
.kb-field > select {
    max-width: 100%;
    text-overflow: ellipsis;
}

.kb-field > input:hover,
.kb-field > select:hover,
.kb-field > textarea:hover {
    border-color: var(--kb-on-surface-var);
}

.kb-field > input:focus,
.kb-field > select:focus,
.kb-field > textarea:focus {
    border-color: var(--kb-primary);
    /* 枠を太くすると幅が変わって揺れるので、内側の影で太さを出す */
    box-shadow: inset 0 0 0 1px var(--kb-primary);
}

/* ---- 浮くラベル ---- */
.kb-field > label {
    position: absolute;
    top: 17px;
    left: 10px;
    padding: 0 4px;
    font-size: 16px;
    line-height: 1.2;
    color: var(--kb-on-surface-var);
    background: var(--kb-surface);
    pointer-events: none;
    transition: transform .15s, font-size .15s, color .15s;
    transform-origin: left top;
    white-space: nowrap;
    max-width: calc(100% - 28px);
    overflow: hidden;
    text-overflow: ellipsis;
}

.kb-field > input:focus ~ label,
.kb-field > input:not(:placeholder-shown) ~ label,
.kb-field > textarea:focus ~ label,
.kb-field > textarea:not(:placeholder-shown) ~ label,
/* select は常に何かが表示されるので、初期状態から浮かせる */
.kb-field > select ~ label {
    transform: translateY(-25px) scale(.75);
    color: var(--kb-on-surface-var);
}

.kb-field > input:focus ~ label,
.kb-field > select:focus ~ label,
.kb-field > textarea:focus ~ label {
    color: var(--kb-primary);
}

/* ---- iOS の日付入力 ---- */

/*
 * appearance: none だけだと iOS では値が中央寄せになり、
 * 他の入力欄と行頭が揃わない。
 */
.kb-field > input[type="date"]::-webkit-date-and-time-value {
    text-align: left;
    margin: 0;
}

/* 未入力時にプレースホルダ扱いされないので、ラベルは常に浮かせる */
.kb-field > input[type="date"] ~ label {
    transform: translateY(-25px) scale(.75);
}

/* iOS で高さが潰れるのを防ぐ */
.kb-field > input[type="date"] {
    -webkit-appearance: none;
    height: 56px;
}

/* ---- select の矢印 ---- */
.kb-field--select > select {
    padding-right: 40px;
    background-image:
        linear-gradient(45deg, transparent 50%, var(--kb-on-surface-var) 50%),
        linear-gradient(135deg, var(--kb-on-surface-var) 50%, transparent 50%);
    background-position:
        calc(100% - 20px) calc(50% + 2px),
        calc(100% - 14px) calc(50% + 2px);
    background-size: 6px 6px, 6px 6px;
    background-repeat: no-repeat;
    cursor: pointer;
}

.kb-field--select > select:disabled {
    color: var(--kb-outline);
    background-color: var(--kb-surface-variant);
    cursor: default;
}

/* 満枠などで選べない選択肢 */
.kb-field--select option:disabled {
    color: var(--kb-outline);
}

/* ---- コード入力欄 ----
 *
 * 大文字化は見た目だけ。値の変換はJSでは入力中に行わない。
 * input イベントで value を書き換えると、iOSの予測変換が壊れて
 * 1回の打鍵で複数文字が入る。
 */
.kb-code-input {
    text-transform: uppercase;
    letter-spacing: .15em;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* プレースホルダは大文字化しない */
.kb-code-input::placeholder {
    text-transform: none;
    letter-spacing: normal;
}

/* ---- 補助テキスト ---- */

/*
   入力欄の下に添える小さな説明。

   以前は .kb-help 自身に margin-top: -18px を付けていた。
   入力欄（.kb-field は下に24pxの余白を持つ）のすぐ下に置いたときに
   間を詰める意図だったが、入力欄以外の直後に置くと
   前の要素へ18px食い込む。送信ボタンの上に置いた注記が
   ボタンに重なっていたのがこれ。

   詰めるのは「入力欄の直後にあるとき」だけにする。
*/
.kb-help {
    display: block;
    margin: 0 0 20px 14px;
    font-size: .8125rem;
    color: var(--kb-on-surface-var);
}

/* 入力欄の直後だけ、間を詰める */
.kb-field + .kb-help {
    margin-top: -18px;
}

/*
   説明が2つ続く場合。
   2つ目にも負の余白が付くと1つ目に重なるので、
   隣接セレクタで1つ目だけに効かせている（上の指定がそれ）。
   2つ目は少しだけ間を詰める。
*/
.kb-help + .kb-help {
    margin-top: -12px;
}

/*
   選択を自動で外したときの案内。

   補助テキストと同じ位置に出るので、色を変えないと
   もとから書かれていた説明文と見分けがつかず読み飛ばされる。
*/
.kb-help--alert {
    color: var(--kb-error);
    font-weight: 500;
}

/* ============================================================
   ボタン
   ============================================================ */

button,
.kb-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    min-height: 48px;
    padding: 12px 24px;
    font-size: 1rem;
    font-family: inherit;
    font-weight: 500;
    color: var(--kb-on-primary);
    background: var(--kb-primary);
    border: 0;
    border-radius: 100px;
    cursor: pointer;
    text-decoration: none;
    transition: background .15s, box-shadow .15s;
}

button:hover,
.kb-button:hover { background: var(--kb-primary-hover); }

button:focus-visible {
    outline: 2px solid var(--kb-primary);
    outline-offset: 2px;
}

button:disabled {
    color: var(--kb-on-surface-var);
    background: var(--kb-outline-variant);
    cursor: default;
}

/* 主ボタンは横幅いっぱい。親指で押しやすい位置に置く */
button[type="submit"] {
    width: 100%;
    margin-top: 8px;
}

/* 副次的なボタン */
button.kb-secondary {
    color: var(--kb-primary);
    background: transparent;
    border: 1px solid var(--kb-outline-variant);
}

button.kb-secondary:hover {
    background: var(--kb-surface-variant);
}

/* ============================================================
   合計金額
   ============================================================ */

.kb-total {
    display: flex;
    /*
     * flex-wrap が無いと、flex-basis: 100% の .kb-total-note が
     * 他の2要素と同じ行に並び、合計幅が必ず画面を超える。
     */
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 4px 8px;
    margin: 0 0 24px;
    padding: 16px 14px;
    background: var(--kb-surface-variant);
    border-radius: var(--kb-radius);
}

.kb-total-label { font-size: .9375rem; }

.kb-total-value {
    font-size: 1.375rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.kb-total-note {
    flex: 1 0 100%;
    font-size: .8125rem;
    color: var(--kb-on-surface-var);
}

/* ============================================================
   コピーボタン
   ============================================================ */

.kb-copy {
    min-height: 36px;
    margin-top: 12px;
    padding: 8px 18px;
    font-size: .875rem;
    color: var(--kb-primary);
    background: transparent;
    border: 1px solid var(--kb-outline-variant);
}

.kb-copy:hover {
    background: rgba(26, 95, 180, .06);
}

/* 押した直後の反応。文言だけだと変化に気づきにくい */
.kb-copy.is-copied {
    color: var(--kb-on-primary);
    background: var(--kb-success);
    border-color: var(--kb-success);
}

.kb-copy.is-failed {
    color: var(--kb-error);
    border-color: var(--kb-error);
    background: transparent;
}

/* URLのように長い値は、入力欄に入れて横に並べる */
.kb-copy-row {
    display: flex;
    align-items: stretch;
    gap: 8px;
    margin: 8px 0 24px;
}

.kb-copy-row input {
    flex: 1;
    min-width: 0;
    padding: 10px 12px;
    font-size: .8125rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    color: var(--kb-on-surface-var);
    background: var(--kb-surface-variant);
    border: 1px solid var(--kb-outline-variant);
    border-radius: var(--kb-radius);
    /* 読むためではなくコピーのための欄。触れるが編集はしない */
    cursor: text;
}

.kb-copy-row .kb-copy {
    flex: 0 0 auto;
    margin-top: 0;
    border-radius: var(--kb-radius);
}

/* ============================================================
   通知
   ============================================================ */

.kb-error,
[role="alert"]:not([hidden]) {
    margin: 0 0 20px;
    padding: 12px 14px;
    font-size: .9375rem;
    color: var(--kb-error);
    background: #fceeed;
    border-left: 4px solid var(--kb-error);
    border-radius: var(--kb-radius);
}

.kb-notice {
    margin: 0 0 20px;
    padding: 12px 14px;
    font-size: .9375rem;
    background: var(--kb-surface-variant);
    border-radius: var(--kb-radius);
}

/* ============================================================
   完了画面
   ============================================================ */

.kb-code {
    margin: 8px 0 16px;
    padding: 20px 14px;
    text-align: center;
    background: var(--kb-surface-variant);
    border-radius: 8px;
}

.kb-code-value {
    display: block;
    font-size: 2rem;
    font-weight: 700;
    letter-spacing: .2em;
    font-variant-numeric: tabular-nums;
    /* 紛らわしい文字を除いた集合なので等幅で読ませる */
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

.kb-code-label {
    display: block;
    margin-bottom: 4px;
    font-size: .8125rem;
    color: var(--kb-on-surface-var);
}

/* 画像は画面幅を超えない */
img,
canvas,
svg,
iframe,
table {
    max-width: 100%;
}

/* QRは中央に */
#kb-result-qr,
#kb-receipt-qr,
#kb-view-receipt-qr,
#kb-link-qr {
    display: flex;
    justify-content: center;
    margin: 16px 0;
}

#kb-result-qr img,
#kb-receipt-qr img,
#kb-view-receipt-qr img,
#kb-link-qr img,
#kb-result-qr canvas,
#kb-receipt-qr canvas,
#kb-view-receipt-qr canvas,
#kb-link-qr canvas {
    max-width: 100%;
    height: auto;
}

/* ============================================================
   定義リスト
   ============================================================ */

dl {
    margin: 0 0 24px;
    padding: 0;
}

dt {
    margin: 12px 0 2px;
    font-size: .8125rem;
    color: var(--kb-on-surface-var);
}

dd {
    margin: 0;
    padding: 0 0 12px;
    border-bottom: 1px solid var(--kb-outline-variant);
    /* URLなど区切りの無い文字列でも折り返す */
    overflow-wrap: anywhere;
}

dd:last-of-type { border-bottom: 0; }

/* ============================================================
   言語切替
   ============================================================ */

.kb-lang {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    margin: 0 0 16px;
}

.kb-lang select { max-width: 100%; }

.kb-lang select {
    min-height: 40px;
    padding: 6px 32px 6px 12px;
    font-size: .9375rem;
    font-family: inherit;
    color: var(--kb-on-surface-var);
    background-color: var(--kb-surface);
    border: 1px solid var(--kb-outline-variant);
    border-radius: 100px;
    appearance: none;
    background-image:
        linear-gradient(45deg, transparent 50%, var(--kb-on-surface-var) 50%),
        linear-gradient(135deg, var(--kb-on-surface-var) 50%, transparent 50%);
    background-position: calc(100% - 18px) 50%, calc(100% - 12px) 50%;
    background-size: 6px 6px;
    background-repeat: no-repeat;
    cursor: pointer;
}

/* ============================================================
   広い画面
   ============================================================ */

@media (min-width: 600px) {
    main { padding-top: 40px; }
    h1 { font-size: 1.75rem; }

    /* 2列に置いた方が視線の移動が短くなるもの */
    .kb-row {
        display: flex;
        gap: 12px;
    }

    /*
     * min-width: 0 が無いと、flex アイテムは min-content 幅より縮まない。
     * 長い option を持つ select が入ると、その幅で押し広げられる。
     */
    .kb-row > .kb-field {
        flex: 1;
        min-width: 0;
    }
}

/* 動きを減らす設定を尊重する */
@media (prefers-reduced-motion: reduce) {
    .kb-field > label,
    button { transition: none; }
}

/* 読み上げ専用。見た目には出さないが読み上げには残す */
.screen-reader-text {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

/* ============================================================
   ハニーポット

   自動投稿対策の入力欄。人には見せないが、DOM からは消さない。
   display:none にすると「隠された欄」と判別されて回避されやすいので、
   画面外へ送り出す形にする。
   ============================================================ */

.kb-honeypot {
    position: absolute !important;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

/* ============================================================
   申請フォームの流れの案内
   ============================================================ */

#kb-owner-apply .kb-notice ol {
    margin: 8px 0 0;
    padding-left: 1.4em;
}

#kb-owner-apply .kb-notice ol li {
    margin-bottom: 4px;
}

/* ============================================================
   問い合わせのやり取り

   本人が書いた分と対応側が書いた分を左右に寄せず、
   色と縁の位置で区別する。チャットUIに寄せると、
   長文のやり取りで読みにくくなる。
   ============================================================ */

.kb-thread-original {
    padding: 16px;
    margin: 0 0 24px;
    background: var(--kb-surface-variant);
    border-radius: var(--kb-radius);
}

.kb-thread-original h2 {
    margin: 0 0 4px;
    font-size: .9375rem;
}

.kb-thread-date {
    margin: 0 0 8px;
    font-size: .8125rem;
    color: var(--kb-on-surface-var);
}

/* 改行をそのまま見せる。入力時の段落を保つ */
.kb-thread-body,
.kb-msg-body {
    white-space: pre-wrap;
    overflow-wrap: break-word;
}

.kb-thread-empty {
    padding: 16px;
    color: var(--kb-on-surface-var);
    background: var(--kb-surface-variant);
    border-radius: var(--kb-radius);
}

.kb-msg {
    padding: 12px 16px;
    margin: 0 0 12px;
    border-left: 4px solid var(--kb-outline-variant);
    background: var(--kb-surface-variant);
    border-radius: 0 var(--kb-radius) var(--kb-radius) 0;
}

/* 対応側からの返信。読む側にとってこれが本題なので目立たせる */
.kb-msg--us {
    border-left-color: var(--kb-primary);
    background: #eef4fc;
}

/* 本人が書いた分は控えめにする */
.kb-msg--you {
    border-left-color: var(--kb-outline);
}

.kb-msg-head {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: baseline;
    margin: 0 0 6px;
    font-size: .8125rem;
}

.kb-msg-author {
    font-weight: 600;
}

.kb-msg-date {
    color: var(--kb-on-surface-var);
}

.kb-thread-sent {
    padding: 12px 16px;
    color: var(--kb-success);
    background: #eaf6ec;
    border-radius: var(--kb-radius);
}

/* 言語切替。予約フォームと同じ位置に置く */
#kb-inquiry .kb-lang {
    display: flex;
    justify-content: flex-end;
    margin: 0 0 8px;
}

/*
   ページ末尾の注記（他の方に共有しないでください）

   入力欄の直後ではなく送信ボタンの下に置くので、
   詰めずにきちんと間を空ける。
*/
#kb-inquiry > .kb-help {
    margin: 32px 0 0;
    padding-top: 16px;
    border-top: 1px solid var(--kb-outline-variant);
}

/* ---- 機械翻訳の注記 ---- */

/*
   訳であることを控えめに、しかし必ず見える形で出す。
   人が書いた返答と機械の訳を同じ重みで読まれると、
   言い回しをめぐる行き違いのもとになる。
*/
.kb-machine {
    margin: 8px 0 0;
    font-size: .75rem;
    color: var(--kb-on-surface-var);
}

.kb-original {
    margin: 8px 0 0;
    font-size: .8125rem;
}

.kb-original > summary {
    cursor: pointer;
    color: var(--kb-primary);
}

.kb-original > .kb-msg-body {
    padding: 8px 0 0;
    color: var(--kb-on-surface-var);
}

/* ============================================================
   予約完了のチケット（預け入れ用・受取用）
   ============================================================ */

.kb-ticket {
    padding: 20px 16px;
    margin: 0 0 20px;
    border: 1px solid var(--kb-outline-variant);
    border-radius: var(--kb-radius);
    text-align: center;
}

/* 受取用は取り扱いが違うので、色で区別する */
.kb-ticket--receipt {
    border-color: var(--kb-primary);
    background: #f4f8fd;
}

.kb-ticket > h3 {
    margin: 0 0 12px;
    font-size: 1rem;
}

.kb-qr {
    display: flex;
    justify-content: center;
    margin: 16px 0 0;
}

.kb-ticket-note {
    margin: 12px 0 0;
    font-size: .8125rem;
    color: var(--kb-on-surface-var);
    text-align: left;
}

/* ============================================================
   一括作業画面

   現場で立ったまま片手で使う。
   押す対象は大きく、読み取った件数は常に見える位置に置く。
   ============================================================ */

#kb-scan {
    max-width: 560px;
}

.kb-scan-head {
    display: flex;
    justify-content: flex-end;
    margin: 0 0 12px;
}

.kb-scan-actor {
    padding: 4px 12px;
    font-size: .8125rem;
    color: var(--kb-on-surface-var);
    background: var(--kb-surface-variant);
    border-radius: 999px;
}

.kb-scan-modes {
    display: grid;
    gap: 12px;
    margin: 24px 0;
}

.kb-scan-mode {
    padding: 24px 16px;
    font-size: 1.0625rem;
}

/* ---- カメラ ---- */

.kb-scan-camera {
    position: relative;
    margin: 0 0 16px;
    overflow: hidden;
    background: #000;
    border-radius: var(--kb-radius);
    /*
       枠に高さを持たせておく。

       video は映像のメタデータが読めるまで縦が0になる。
       高さ0の要素は描画されないとみなされ、iOS Safari では
       再生が始まらずフレームも出ない。
       先に場所を確保しておくことで、再生の開始条件を満たす。
    */
    min-height: 240px;
}

.kb-scan-camera > video {
    display: block;
    width: 100%;
    /* 高さ0にさせない。理由は上の min-height と同じ */
    min-height: 240px;
    height: auto;
    /* 端末を縦向きにしたときに縦長になりすぎないようにする */
    max-height: 60vh;
    object-fit: cover;
    background: #000;
}

/* 読み取り位置の目安。中央に置くとQRを合わせやすい */
.kb-scan-reticle {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 60%;
    aspect-ratio: 1 / 1;
    transform: translate(-50%, -50%);
    border: 2px solid rgba(255, 255, 255, .85);
    border-radius: 8px;
    pointer-events: none;
}

.kb-scan-hint {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    margin: 0;
    padding: 8px 12px;
    font-size: .875rem;
    color: #fff;
    text-align: center;
    background: rgba(0, 0, 0, .55);
}

.kb-scan-hint--added     { background: rgba(26, 127, 55, .85); }
.kb-scan-hint--duplicate { background: rgba(153, 104, 0, .85); }
.kb-scan-hint--invalid,
.kb-scan-hint--full      { background: rgba(179, 38, 30, .85); }

.kb-scan-manual {
    margin: 0 0 16px;
    font-size: .875rem;
}

.kb-scan-manual > summary {
    cursor: pointer;
    color: var(--kb-primary);
    margin-bottom: 12px;
}

/* ---- 読み取り件数 ---- */

.kb-scan-counter {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 8px;
    padding: 12px 16px;
    margin: 0 0 12px;
    background: var(--kb-surface-variant);
    border-radius: var(--kb-radius);
}

.kb-scan-counter > output {
    font-size: 1.75rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.kb-diff-match { color: var(--kb-success); font-weight: 600; }
.kb-diff-short { color: var(--kb-error);   font-weight: 600; }
.kb-diff-over  { color: #996800;           font-weight: 600; }

.kb-scan-list {
    max-height: 40vh;
    margin: 0 0 16px;
    padding: 0;
    overflow-y: auto;
    list-style: none;
}

.kb-scan-list > li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 12px;
    border-bottom: 1px solid var(--kb-outline-variant);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: .875rem;
}

.kb-scan-remove {
    width: 32px;
    min-height: 32px;
    padding: 0;
    font-size: 1.125rem;
    line-height: 1;
    color: var(--kb-on-surface-var);
    background: transparent;
    border: 1px solid var(--kb-outline-variant);
}

/* ---- 予約と確認 ---- */

.kb-scan-booking,
.kb-scan-card {
    padding: 16px;
    margin: 0 0 16px;
    background: var(--kb-surface-variant);
    border-radius: var(--kb-radius);
}

.kb-scan-card--warn {
    background: #fdf6e7;
    border-left: 4px solid #996800;
}

.kb-scan-card > h3 {
    margin: 0 0 8px;
    font-size: 1rem;
}

.kb-scan-blocked {
    color: var(--kb-error);
    font-weight: 600;
}

.kb-scan-dl {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 4px 16px;
    margin: 0;
}

.kb-scan-dl > dt {
    color: var(--kb-on-surface-var);
    font-size: .875rem;
}

.kb-scan-dl > dd {
    margin: 0;
    font-weight: 500;
}

/* 補助的な操作は目立たせない */
.kb-button-sub {
    color: var(--kb-primary);
    background: transparent;
    border: 1px solid var(--kb-outline-variant);
}

/* ============================================================
   トップの入口一覧
   ============================================================ */

.kb-entry-list {
    margin: 0 0 24px;
    padding: 0;
    list-style: none;
}

.kb-entry-list > li {
    border-bottom: 1px solid var(--kb-outline-variant);
}

.kb-entry-list > li > a {
    display: block;
    padding: 16px 4px;
    text-decoration: none;
}

.kb-entry-list > li > a:hover {
    background: var(--kb-surface-variant);
}

/*
   関係者向けの見出し。
   利用者が押す必要のない項目なので、区切りをはっきり出す。
*/
.kb-entry-heading {
    margin: 40px 0 8px;
    padding-top: 24px;
    font-size: .9375rem;
    color: var(--kb-on-surface-var);
    border-top: 1px solid var(--kb-outline-variant);
}

/* ============================================================
   荷物の内訳（サイズごとの行）
   ============================================================ */

.kb-item-row {
    position: relative;
    padding: 0 0 0;
    margin: 0 0 8px;
}

/*
   削除ボタン

   行の右上に小さく置く。サイズと個数の入力を狭めたくないので、
   入力欄の列には入れずに重ねる。
*/
.kb-item-remove {
    position: absolute;
    top: -4px;
    right: 0;
    width: auto;
    min-height: 0;
    padding: 2px 8px;
    font-size: .75rem;
    color: var(--kb-on-surface-var);
    background: transparent;
    border: 1px solid var(--kb-outline-variant);
    border-radius: var(--kb-radius);
}

.kb-item-remove:hover {
    color: var(--kb-error);
    border-color: var(--kb-error);
    background: transparent;
}

/* 行が1つだけのときは非表示。全部消せると0個の予約になる */
.kb-item-remove[hidden] {
    display: none;
}

#kb-item-add {
    width: auto;
    min-height: 44px;
    padding: 10px 20px;
    font-size: .9375rem;
}

/* ---- 読み取り一覧の状態 ----

   読んだ直後は「確認中」で入り、サーバの応答で印が変わる。
   対象外のものを消さずに残すのは、なぜ数に入らないのかを
   その場で分かるようにするため。
*/

.kb-scan-list > li {
    gap: 8px;
}

.kb-scan-mark {
    flex: 0 0 auto;
    width: 20px;
    text-align: center;
    font-weight: 700;
}

.kb-scan-list > li.is-ok       .kb-scan-mark { color: var(--kb-success); }
.kb-scan-list > li.is-checking .kb-scan-mark { color: var(--kb-outline); }
.kb-scan-list > li.is-warn     .kb-scan-mark { color: #996800; }
.kb-scan-list > li.is-bad      .kb-scan-mark { color: var(--kb-error); }

/* 対象にならない行は落として、目線が成功分に向くようにする */
.kb-scan-list > li.is-warn,
.kb-scan-list > li.is-bad {
    background: #fdf6e7;
}

.kb-scan-list > li.is-bad {
    background: #fdf0ef;
}

.kb-scan-code {
    flex: 0 0 auto;
    font-size: .8125rem;
    color: var(--kb-on-surface-var);
}

.kb-scan-note {
    flex: 1 1 100%;
    font-size: .75rem;
    color: var(--kb-on-surface-var);
    font-family: inherit;
}

.kb-scan-list > li {
    flex-wrap: wrap;
}

/* ---- 読み取りの合図（見た目） ----

   消音のiPhoneでは音も振動も出せないので、
   目で分かる合図が唯一の手がかりになる。

   小さな印だと、荷物を持って手元を見ている間に気づけない。
   カメラの枠ごと光らせて、視界の端でも分かるようにする。
*/

.kb-scan-camera::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    opacity: 0;
    /* 枠の内側に太い縁を出す。中央の映像は隠さない */
    box-shadow: inset 0 0 0 10px currentColor;
}

.kb-scan-camera.is-hit::after {
    color: #2bd576;
    animation: kb-flash .4s ease-out;
}

.kb-scan-camera.is-miss::after {
    color: #ff5a4e;
    animation: kb-flash .4s ease-out;
}

@keyframes kb-flash {
    0%   { opacity: 1; }
    70%  { opacity: .85; }
    100% { opacity: 0; }
}

/* 読み取り件数も一緒に動かす。数が増えたことが分かる */
.kb-scan-camera.is-hit ~ * .kb-scan-counter > output,
.kb-scan-counter > output.is-bumped {
    animation: kb-bump .3s ease-out;
}

@keyframes kb-bump {
    0%   { transform: scale(1); }
    40%  { transform: scale(1.35); color: var(--kb-success); }
    100% { transform: scale(1); }
}

/*
   動きを減らす設定にしている端末では光らせない。
   ただし完全に消すと合図が無くなるので、色だけ残す。
*/
@media (prefers-reduced-motion: reduce) {
    .kb-scan-camera.is-hit::after,
    .kb-scan-camera.is-miss::after {
        animation: none;
        opacity: .6;
    }
}

/* ---- 全画面の合図 ----

   消音のiPhoneでは音も振動も出せない。
   iOS 18.4 以降、Appleがハプティクスに操作を必須にしたため、
   カメラの読み取りループからは振動を出す手段が無い。

   残るのは見た目だけなので、画面いっぱいに出す。
   手元の荷物を見ていても、持っている端末が光れば気づける。
*/

.kb-flash {
    position: fixed;
    inset: 0;
    z-index: 9999;
    opacity: 0;
    pointer-events: none;
}

.kb-flash.is-hit {
    background: #2bd576;
    animation: kb-screen-flash .4s ease-out;
}

.kb-flash.is-miss {
    background: #ff5a4e;
    animation: kb-screen-flash .4s ease-out;
}

@keyframes kb-screen-flash {
    /*
       強すぎると連続で読むときに目が疲れる。
       一瞬だけ濃く出して、すぐ引く。
    */
    0%   { opacity: .55; }
    35%  { opacity: .30; }
    100% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
    .kb-flash.is-hit,
    .kb-flash.is-miss {
        animation: none;
        opacity: .3;
        transition: opacity .3s;
    }
}

/* ============================================================
   予約の変更
   ============================================================ */

#kb-edit-entry,
#kb-edit-form-wrap {
    padding: 20px 16px;
    margin: 32px 0 0;
    border: 1px solid var(--kb-outline-variant);
    border-radius: var(--kb-radius);
}

#kb-edit-entry > h3,
#kb-edit-form-wrap > h3 {
    margin: 0 0 12px;
}

#kb-edit-deadline-note {
    margin: 0 0 16px;
}

/*
   取り消しのボタン

   変更フォームの中に置くと、保存のつもりで押される。
   線で区切って離し、色も控えめにする。
   押した先で確認を挟むので、ここで赤くして身構えさせる必要はない。
*/
.kb-edit-cancel {
    margin: 24px 0 0;
    padding-top: 20px;
    border-top: 1px solid var(--kb-outline-variant);
    text-align: center;
}

.kb-edit-cancel > button {
    width: auto;
    min-height: 44px;
    padding: 10px 24px;
    font-size: .875rem;
    color: var(--kb-error);
    border-color: var(--kb-outline-variant);
}

/* ============================================================
   マニュアルへのリンク（一括作業ページ）

   管理画面フッターと同じ部品を、現場の画面でも使う。
   HTMLはPHP側の kb_manual_render() が組み立てるので、
   admin.css と同じクラス名で、この画面向けの見た目だけを当てる。
   ============================================================ */

#kb-scan-docs {
    margin-top: 40px;
    padding-top: 24px;
    border-top: 1px solid var(--kb-outline-variant);
}

.kb-manual-wrap {
    --kb-manual-cols: 4;
    --kb-manual-gap: 10px;

    display: flex;
    flex-wrap: wrap;
    gap: var(--kb-manual-gap);
    width: 100%;
}

.kb-manual-head {
    flex: 0 0 100%;
    font-weight: 600;
    color: var(--kb-on-surface-var);
}

/*
   1枚あたりの幅

   行に並ぶ数だけ隙間があるので、その分を引いてから割る。
   スマホでは min-width が効いて、勝手に1〜2列になる。
*/
.kb-manual {
    flex: 1 1 calc(
        (100% - (var(--kb-manual-cols) - 1) * var(--kb-manual-gap))
        / var(--kb-manual-cols)
    );
    min-width: 150px;
    box-sizing: border-box;
    background: var(--kb-surface);
    border: 1px solid var(--kb-outline-variant);
    border-radius: var(--kb-radius);
}

.kb-manual > strong {
    display: block;
    padding: 10px 12px;
    font-size: .9375rem;
    background: var(--kb-surface-variant);
    border-bottom: 1px solid var(--kb-outline-variant);
    border-radius: var(--kb-radius) var(--kb-radius) 0 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.kb-manual > a {
    /* 現場では指で押すので、リンクでも高さを確保する */
    display: block;
    min-height: 44px;
    padding: 12px;
    font-size: .875rem;
    text-decoration: none;
}

.kb-manual > a > span {
    display: inline-block;
    margin-right: 4px;
    font-size: .625rem;
    transform: scale(.8);
    transform-origin: 50% 50%;
}

/* ============================================================
   積荷リスト  /manifest/{token}/
   ============================================================ */

#kb-manifest {
    max-width: 900px;
}

.kb-manifest-head {
    margin-bottom: 28px;
}

.kb-manifest-meta {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 4px 16px;
    margin: 0 0 16px;
}

.kb-manifest-meta dt {
    font-size: .8125rem;
    color: var(--kb-on-surface-var);
}

.kb-manifest-meta dd {
    margin: 0;
    font-size: .9375rem;
}

.kb-manifest-dest {
    margin: 0 0 32px;
    /* 印刷で行き先が2ページにまたがらないようにする */
    break-inside: avoid;
}

.kb-manifest-dest > h2 {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
    margin: 0 0 4px;
    padding: 10px 12px;
    background: var(--kb-surface-variant);
    border-radius: var(--kb-radius);
}

.kb-manifest-dest-count {
    flex: 0 0 auto;
    font-size: .9375rem;
    font-weight: 400;
}

.kb-manifest-from {
    margin: 16px 0 6px;
    font-size: .9375rem;
    color: var(--kb-on-surface-var);
}

.kb-manifest-from > span {
    margin-left: 8px;
    font-weight: 400;
}

.kb-manifest-table {
    width: 100%;
    border-collapse: collapse;
    font-size: .875rem;
}

.kb-manifest-table th,
.kb-manifest-table td {
    padding: 8px 10px;
    text-align: left;
    vertical-align: top;
    border-bottom: 1px solid var(--kb-outline-variant);
}

.kb-manifest-table thead th {
    font-size: .75rem;
    font-weight: 600;
    color: var(--kb-on-surface-var);
    border-bottom-width: 2px;
}

.kb-col-check { width: 44px; }
.kb-col-code  { width: 120px; }
.kb-col-name  { width: 22%; }

/* 現場でペンを入れるための枠。印刷しても残る */
.kb-checkbox {
    display: inline-block;
    width: 16px;
    height: 16px;
    border: 1.5px solid var(--kb-outline);
    border-radius: 2px;
}

.kb-manifest-partial {
    display: block;
    margin-top: 2px;
    font-size: .6875rem;
    color: var(--kb-error);
}

.kb-manifest-sign {
    margin-top: 40px;
    padding-top: 16px;
    border-top: 1px solid var(--kb-outline-variant);
}

.kb-manifest-sign-line {
    margin-top: 28px;
    letter-spacing: .05em;
}

.kb-manifest-foot {
    margin-top: 24px;
    font-size: .8125rem;
    color: var(--kb-on-surface-var);
}

/* ============================================================
   預かり証

   画面には出さず、印刷のときだけ現れる。
   ============================================================ */

.kb-receipt-doc {
    /*
       hidden 属性が付いている間は出ない。
       JSが値を入れ終えたら外れるが、それでも画面には出したくないので
       印刷メディア以外では隠しておく。
    */
    display: none;
}

.kb-receipt-print-action {
    margin-top: 24px;
}

/* ============================================================
   印刷

   ・積荷リスト   … そのまま刷る。操作ボタンだけ落とす
   ・預かり証     … 預かり証だけを刷る。他は全部落とす
   ============================================================ */

@media print {

    .kb-no-print,
    .kb-copy-button {
        display: none !important;
    }

    body {
        background: #fff;
        color: #000;
    }

    main {
        max-width: none;
        padding: 0;
    }

    a {
        color: #000;
        text-decoration: none;
    }

    /*
       預かり証を刷るとき

       タグ画面には状態の表示や入力欄も載っている。
       印刷では預かり証だけにしたいので、main の直下を一度すべて隠し、
       預かり証だけを出し直す。
    */
    #kb-tag > * {
        display: none !important;
    }

    #kb-tag > .kb-receipt-doc {
        display: block !important;
        max-width: 80mm;   /* レシートプリンタでも破綻しない幅 */
    }

    .kb-receipt-head {
        text-align: center;
        margin-bottom: 12px;
        padding-bottom: 8px;
        border-bottom: 1px solid #000;
    }

    .kb-receipt-head h2 {
        margin: 0 0 4px;
        font-size: 13pt;
    }

    .kb-receipt-issuer {
        margin: 0;
        font-size: 10pt;
    }

    .kb-receipt-body {
        display: grid;
        grid-template-columns: auto 1fr;
        gap: 4px 10px;
        margin: 0 0 12px;
        font-size: 9pt;
    }

    .kb-receipt-body dt {
        color: #444;
    }

    .kb-receipt-body dd {
        margin: 0;
        font-weight: 600;
    }

    .kb-receipt-code {
        font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
        letter-spacing: .12em;
    }

    .kb-receipt-pickup {
        margin: 12px 0;
        padding: 10px;
        text-align: center;
        border: 1.5px solid #000;
    }

    .kb-receipt-pickup-label {
        margin: 0;
        font-size: 8pt;
    }

    .kb-receipt-pickup-code {
        margin: 2px 0 8px;
        font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
        font-size: 20pt;
        font-weight: 700;
        letter-spacing: .16em;
    }

    .kb-receipt-qr img,
    .kb-receipt-qr canvas {
        display: block;
        margin: 0 auto;
    }

    .kb-receipt-pickup-note {
        margin: 8px 0 0;
        font-size: 7.5pt;
        line-height: 1.4;
    }

    .kb-receipt-price {
        width: 100%;
        margin: 12px 0;
        border-collapse: collapse;
        font-size: 9pt;
    }

    .kb-receipt-price th,
    .kb-receipt-price td {
        padding: 3px 0;
        text-align: left;
    }

    .kb-receipt-price td {
        text-align: right;
    }

    .kb-receipt-price tfoot th,
    .kb-receipt-price tfoot td {
        padding-top: 6px;
        font-size: 11pt;
        border-top: 1px solid #000;
    }

    /* 領収書と取り違えられないように、目立つ位置に置く */
    .kb-receipt-disclaimer {
        margin: 10px 0;
        padding: 6px;
        font-size: 8pt;
        line-height: 1.5;
        text-align: center;
        border: 1px dashed #000;
    }

    .kb-receipt-foot {
        margin: 8px 0 0;
        font-size: 7.5pt;
        color: #444;
    }

    /* 積荷リストは幅を絞らない */
    #kb-manifest {
        max-width: none;
    }

    .kb-manifest-table {
        font-size: 9pt;
    }

    .kb-manifest-dest > h2 {
        background: none;
        border-bottom: 2px solid #000;
        border-radius: 0;
        padding-left: 0;
        padding-right: 0;
    }
}
