# 消えた Google スプレッドシートの埋め込みを、サイトの中の表に置き換える（2026-11-08）
import csv, io, html, sys
OUT = sys.argv[1]
JS = open('/tmp/claude-0/sheets/height.js', encoding='utf-8').read()

CSS = """<style>html{font-variant-numeric:tabular-nums}
*{box-sizing:border-box}
body{margin:0;background:#f7f7f7;color:#242424;font-family:'Inter','Noto Sans JP',sans-serif;padding:8px 0}
.wrap{max-width:720px;margin:0 auto;background:#fff;border-radius:8px;padding:24px 24px 20px}
.lab{font-size:12px;letter-spacing:.08em;color:#888;margin:0 0 12px}
table{width:100%;border-collapse:collapse;font-size:13px;line-height:1.7}
th{white-space:nowrap;text-align:left;font-weight:700;font-size:12px;color:#555;padding:8px 10px;border-bottom:1px solid #242424;vertical-align:bottom}
td{padding:10px;border-bottom:1px solid #e6e6e6;vertical-align:top}
tr:last-child td{border-bottom:0}
td.k{font-weight:700;white-space:nowrap}
td.n{white-space:nowrap}
.src{margin:14px 0 0;font-size:11px;color:#888;line-height:1.6}
/* 列の多い表と、スマホでは、1行を1つの欄にする */
.stack table,.stack tbody,.stack tr,.stack td{display:block;width:100%}
.stack thead{display:none}
.stack tr{background:#f7f7f7;border-radius:8px;padding:14px 16px;margin:0 0 10px}
.stack tr:last-child{margin-bottom:0}
.stack td{border:0;padding:0 0 8px}
.stack td:last-child{padding-bottom:0}
.stack td::before{content:attr(data-h);display:block;font-size:11px;letter-spacing:.08em;color:#888}
.stack td.k{font-size:15px;white-space:normal;padding-bottom:10px}
.stack td.k::before{display:none}
@media (max-width:560px){
 .wrap{padding:20px 16px 16px}
 .auto table,.auto tbody,.auto tr,.auto td{display:block;width:100%}
 .auto thead{display:none}
 .auto tr{background:#f7f7f7;border-radius:8px;padding:14px 16px;margin:0 0 10px}
 .auto tr:last-child{margin-bottom:0}
 .auto td{border:0;padding:0 0 8px;white-space:normal}
 .auto td:last-child{padding-bottom:0}
 .auto td::before{content:attr(data-h);display:block;font-size:11px;letter-spacing:.08em;color:#888}
 .auto td.k{font-size:15px;padding-bottom:10px}
 .auto td.k::before{display:none}
}
</style>"""

def page(title, lab, csvtext, mode='auto', note=None, nowrap=()):
    rows = list(csv.reader(io.StringIO(csvtext.strip())))
    head, body = rows[0], rows[1:]
    e = html.escape
    th = ''.join('<th>%s</th>' % e(h) for h in head)
    trs = []
    for r in body:
        tds = []
        for i, (h, v) in enumerate(zip(head, r)):
            cls = ' class="k"' if i == 0 else (' class="n"' if i in nowrap else '')
            tds.append('<td%s data-h="%s">%s</td>' % (cls, e(h), e(v).replace('\n', '<br>')))
        trs.append('<tr>' + ''.join(tds) + '</tr>')
    n = '<p class="src">%s</p>' % e(note) if note else ''
    return ('<!doctype html>\n<html lang="ja">\n<head>\n<meta charset="utf-8">\n'
            '<meta name="viewport" content="width=device-width,initial-scale=1">\n'
            '<title>%s</title>\n<link rel="preconnect" href="https://fonts.googleapis.com">\n'
            '<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&family=Noto+Sans+JP:wght@400;500;700&display=swap" rel="stylesheet">\n'
            '%s\n</head>\n<body>\n<div class="wrap %s">\n<p class="lab">%s</p>\n'
            '<table><thead><tr>%s</tr></thead><tbody>\n%s\n</tbody></table>\n%s\n</div>\n%s\n</body>\n</html>\n'
            ) % (e(title), CSS, mode, e(lab), th, '\n'.join(trs), n, JS)

def screens(lab, csvtext):
    rows = list(csv.reader(io.StringIO(csvtext.strip())))[1:]
    e = html.escape
    H = ['画面ID', '画面名', 'ターゲットユーザー', '機能概要・要件', '優先度', '対応進捗']
    out, cur = [], None
    for name, cat, sid, dev, who, what, pri, st in rows:
        if cat != cur:
            cur = cat
            out.append('<tr class="g"><td colspan="6">%s<span>%s</span></td></tr>' % (e(cat), e(dev)))
        v = [sid, name, who, what, pri.split('（')[0], st]
        out.append('<tr>' + ''.join('<td%s data-h="%s">%s</td>' % (c, e(h), e(x)) for h, x, c in zip(H, v, ['', ' class="k"', '', '', ' class="n"', ' class="n"'])) + '</tr>')
    t = page(lab, lab, '画面ID,画面名,ターゲットユーザー,機能概要・要件,優先度,対応進捗\nx,x,x,x,x,x', 'auto scr')
    t = t.replace('<td class="k" data-h="画面ID">x</td>', '', 1)
    a, b = t.index('<tbody>') + 7, t.index('</tbody>')
    extra = ('<style>.scr td:first-child{white-space:nowrap;color:#555}.scr td.k{white-space:normal}'
             '.scr tr.g td{background:#f7f7f7;font-weight:700;font-size:12px;padding:8px 10px;border-bottom:0}'
             '.scr tr.g td span{font-weight:400;color:#888;margin-left:10px}'
             '@media (max-width:560px){.scr tr.g{background:none;padding:12px 0 4px;margin:0}.scr tr.g td{background:none;padding:0}.scr tr.g td::before{display:none}'
             '.scr tr.g td span{display:block;margin:0}.scr td.k{font-size:15px}}</style>')
    t = t[:a] + '\n' + '\n'.join(out) + '\n' + t[b:]
    return t.replace('</head>', extra + '\n</head>', 1)

T = {}
T['target'] = ("ターゲットユーザーと利用シナリオ", """項目,薬剤搬送ロボットの定義案,補足・要件への影響
ターゲットユーザー,病院の看護師、薬剤師、医療スタッフ,忙しい環境での迅速な操作、非専門家でも直感的に使えるUIが必須。
主な利用環境,病院の病棟、廊下、エレベーター、ナースステーション、薬局,狭い通路での走行安定性、エレベーター連携、低騒音、衛生面が要件に。
主なタスク,薬剤（注射薬、内服薬など）や検体（血液など）の指定場所への搬送,セキュリティ（薬剤盗難防止）、温度管理、搬送状況のリアルタイム監視が要件に。
HRIの目的,スタッフの負担軽減、作業効率向上、心理的安全性の確保,愛着や親しみやすさを持てるデザイン（顔UI）、明確なステータス表示が重要。
""", 'auto')
T['hw'] = ("ハードウェアと安全性の寸法要件", """要件カテゴリ,寸法/値,根拠と要件への反映
ロボットの高さ,1150 mm（約1.15 m）,看護師の作業、車椅子利用者との目線に配慮した設計。
薬剤取り出し高さ,約750 mm,人間工学的な高さ。看護師が自然な姿勢で薬剤を取り出せる。
ロボットの幅/奥行,520 mm,病院の標準的な通路や病室のドアを通過できる最小限の幅を確保。
通路の想定幅,約2000 mm（2.0 m）,ストレッチャー（600 mm）と搬送ロボット（520 mm）がすれ違う環境を想定。
最小安全クリアランス,400 mm 超,安全規格に基づいたすれ違い時の最小間隔の確保。
重量,最大積載時でも医療スタッフが緊急時に手動で動かせる程度（想定）,故障時や緊急停止時の対応能力に影響。
""", 'auto')
T['ui'] = ("ロボット本体のUI要素", """UI要素,要件,デザイナーの役割
顔（ディスプレイ）,感情表現（笑顔、困惑など）、タスクステータス表示,キャラクターデザイン、アニメーション設計。親しみやすさと状況理解のしやすさのバランス。
ステータス表示,進行方向、バッテリー残量、積載部の施錠状態（色やアイコンで表示）,視認性の高いインジケーターデザイン（側面の光るリングなど）。
操作インターフェース,タッチパネルによる目的地入力、薬剤受け渡し確認（ID/パスワード）,直感的な情報階層、ミスタッチ防止、多忙なスタッフでも迅速に操作できるフローの設計。
""", 'auto')
T['screens'] = ("UI/UXデザイン画面リスト", """画面名,カテゴリ,画面ID,使用デバイス,ターゲットユーザー,機能概要・要件,優先度,対応進捗
待機・表情画面,1. Robot HMI,R-01,ロボット本体（タッチパネル）,全員,アイドリング時の表情／充電・待機ステータス,★★★（高）,完了
認証画面,1. Robot HMI,R-02,ロボット本体（タッチパネル）,薬剤師・看護師,顔認証／パスワード入力,★★★（高）,完了
目的地選択画面,1. Robot HMI,R-03,ロボット本体（タッチパネル）,薬剤師,病棟・ステーション選択／フロアマップ表示,★★★（高）,完了
薬剤投入・確認画面,1. Robot HMI,R-04,ロボット本体（タッチパネル）,薬剤師,ドロワー解錠・施錠／投入完了ボタン,★★★（高）,完了
走行中ステータス画面,1. Robot HMI,R-05,ロボット本体（タッチパネル）,すれ違う人,進行方向表示／メッセージ表示,★★★（高）,完了
受取・取出画面,1. Robot HMI,R-06,ロボット本体（タッチパネル）,看護師,到着時認証／ドロワー解錠／受取完了,★★★（高）,完了
エラー・緊急停止画面,1. Robot HMI,R-07,ロボット本体（タッチパネル）,全員・保守,障害物検知時の表情／緊急停止ボタン,★★★（高）,完了
ダッシュボード,2. Admin Web,A-01,PC／タブレット（Web）,運用管理者,全機体位置表示／稼働ステータス一覧,★★★（高）,完了
搬送タスク管理,2. Admin Web,A-02,PC／タブレット（Web）,運用管理者,配送リクエスト一覧／スケジュール管理,★★☆（中）,完了
履歴・ログ確認,2. Admin Web,A-03,PC／タブレット（Web）,運用管理者,搬送履歴ログ／エラー詳細ログ,★★☆（中）,完了
機体設定・管理,2. Admin Web,A-04,PC／タブレット（Web）,保守担当者,バッテリー詳細／ファームウェア更新,★☆☆（低）,完了
到着通知・パス表示,3. Staff App,M-01,スマートフォン／タブレット,看護師,到着通知ポップアップ／解錠パス表示,★★☆（中）,完了
集荷リクエスト,3. Staff App,M-02,スマートフォン／タブレット,看護師,呼出ボタン／到着予定確認,★☆☆（低）,完了
プロフィール,3. Staff App,M-03,スマートフォン／タブレット,看護師,プロフィール／アプリ設定／サポート,★☆☆（低）,完了
""", 'screens')
T['face'] = ("ロボットの顔パターン案（12パターン）", """パターン,デザインのポイント,印象,適した場面
標準笑顔,縦長の目、細やかな口,シンプル、親しみやすい,通常時、待機中
にっこり笑顔,口角を上げる、目を細める,とても親しみやすい,挨拶、完了時
真剣な表情,目をキリッと、口を引き締める,頼りがいがある,搬送中、重要表示
丸い目,目をまん丸にする,可愛い、愛嬌がある,小児科、和ませたい時
眉毛を追加,目の上に眉毛を追加,表情豊か、人間らしい,困った時、考え事
ウィンク,片目を弓なりに閉じ、もう片方は開けたままにする。口角は上げる。,お茶目、親しみの情、遊び心,すれ違いざまの挨拶、軽いタスク完了時、ジョークへの反応。
スリープ（充電中）,両目を閉じた形（「U」の字を逆にしたような弧線、または横棒）にする。口は小さくする。,安らか、休息中、静か,充電ステーションにいる時、待機モードで省エネ中の時。
驚いた顔,目を普段より大きく真ん丸に見開き、口も小さく丸く（「O」の形）開ける。,びっくり、予期せぬ事態、純粋な反応,突然障害物を検知した時、大きな音がした時、新しい情報を認識した瞬間。
困った顔（考え中）,眉毛を「ハ」の字にし、口を少し「へ」の字（または波線）にする。視線をわずかに斜め上に向けるとなお良い。,少し困惑、思考中、人間味がある,複雑なルート計算中、軽いエラーで再試行中の時、指示が聞き取れなかった時。
キラキラした目,目の白い部分の中に、星形や菱形のハイライトを追加して輝きを強調する。,期待、喜び、達成感、スペシャルな感じ,重要な任務を完了した時、褒められた時、特別なイベント時。
テレ顔（頬紅）,目の下に、淡い水色（または薄いピンク）の楕円形や斜線を追加して、頬を赤らめているように表現する。,照れくさい、謙虚、可愛らしい,患者さんやスタッフに「ありがとう」と言われた時、注目を浴びた時。
めまい,黒目が左右で上下反対になっている。口元が波打っているように表現する。,不安定な様子,何かにあたってよろけてしまった時、段差を乗り越えて不安定な時。
""", 'auto')
T['shift'] = ("ロボット24時間シフト表（12台）", """時間帯,チームA（5台）,チームB（5台）,フリー（2台）,現場の状態
8:00,稼働,充電・待機,メンテ／待機,5台稼働
13:50,順次帰還開始,順次出動開始,待機,★交代タイム
14:00,充電・待機,稼働,待機,5台稼働
19:50,順次出動開始,順次帰還開始,待機,★交代タイム
20:00,稼働,充電・待機,待機,5台稼働
1:50,順次帰還開始,順次出動開始,待機,★交代タイム
2:00,充電・待機,稼働,待機,5台稼働
7:50,順次出動開始,順次帰還開始,待機,★交代タイム
""", 'auto')
T['hri'] = ("薬剤搬送ロボットハコブくん：HRIデザイン変数一覧", """変数名,カテゴリ,設計値,HRIデザインの意図
通常移動速度,速度,0.7 m/s,看護師の平均歩行速度よりやや遅く設定し、威圧感を排除。
夜間モード速度,速度,0.4 m/s,静音性（40dB以下）を優先し、患者の睡眠を妨げない低速走行。
加減速カーブ,速度,0.2 m/s²,急な始動・停止を避け、搬送中の薬剤の安定と周囲への予測可能性を確保。
機体全幅,距離,510 mm,有効幅員1.2mの廊下で人間とストレスなくすれ違えるサイズ（制約520mm以下）。
安全停止距離,距離,0.6 m,LiDAR検知に基づき、接触を完全に回避する絶対停止ライン。
回避・戻り開始,距離,2.5 m,遠方から進路を微調整し、看護師に「気づいている」ことを伝える予備動作距離。
通常動作音,音,45 dB,病院の日中環境音（50dB）を下回り、業務を阻害しない静かさ。
夜間動作音,音,40 dB,図書館レベルの静寂。振動音や通知音の周波数を低域にシフト。
完了通知音,音,Soft Chime,「薬剤取り違え」を防ぐための、注意を引くが不快でない高調波設計。
サイドLED状態,光,RGB / 300cd,青：正常移動、緑：完了、赤：エラー。遠くからでも状態が直感的にわかる。
庫内高演色LED,光,CRI > 90,薄暗い夜間の病棟でも、薬剤名や色の識別ミスを防ぐ高精度な照明。
引出し高さ,身体,750 mm,看護師が腰を曲げずに自然な姿勢で操作できる、机の高さに合わせた人間工学設計。
""", 'auto')
T['light'] = ("ハコブくん側面発光仕様（3ステート）", """ステート,色,動き・リズム,表現する意図・メッセージ,Serve Roboticsでの対応表現（推測含む）
待機中,白／淡青,ゆっくりとしたブリージング（呼吸）,正常稼働中、指示待ち。穏やか。,ニュートラルな表情、ゆっくり周囲を見回す
移動中,青／グリーン,定常光、または進行方向へのフロー,活動中、移動エネルギー。進路注意。,進行方向を見つめる視線、ウィンカー
ヘルプ要請,黄／アンバー,早めのパルス点滅、不規則なゆらぎ,軽度の異常、介入要求。困惑。,困った表情、停止して周囲を見る、特殊な点滅パターン
""", 'auto')
T['time'] = ("時間帯別ターゲット", """時間帯,ターゲット層,心理状態・状況,投稿内容の方向性,4コマ漫画の活用例
朝（7:00〜9:00）,通勤・通学者／早朝勤務者,これから一日が始まる／情報収集／気合を入れたい,エール、活力／前向きなメッセージ／一日の活力になる内容,ハコブくんが元気に働く様子／「今日も一日頑張ろう！」というメッセージ／クスッと笑えて目が覚めるネタ
昼（12:00〜13:00）,学生／会社員／主婦（主夫）,昼休憩／リラックス／気分転換,癒し、共感、話題／午後の活力になる内容／誰かと話したくなるネタ,ハコブくんの失敗談や「あるある」ネタ／ほっこりするエピソード／ランチタイムに関連したネタ
夜（20:00〜23:00）,帰宅後の人々／夜勤者／学生,一日の終わり／リラックス／趣味の時間／明日への準備,労い、癒し、深い共感／一日の疲れを癒す内容／考えさせられる内容／明日への希望,一日の仕事を終えたハコブくん／「お疲れ様」のメッセージ／少し感動的なエピソード／夜勤中のハコブくんの様子
""", 'stack')
T['manga'] = ("4コママンガプロット（第1〜3話）", """タイトル,テーマ,登場人物,1コマ目（起）,2コマ目（承）,3コマ目（転）,4コマ目（結）,Design Note
第1話　チョコレート差し入れ,ロボットが提供する機能以上の「癒やし」の効果。,夜勤中の疲れた看護師、ハコブくん（ロボット）,忙しい夜勤の合間、必要な薬剤を運んできたロボットが到着。看護師が操作する。,ロボットの下部にある収納トレイが開き、必要な薬剤を取り出す。看護師の表情はまだ業務モードで硬い。,薬剤ケースの下に、先輩からの小さなメモ用紙と、個包装のチョコレートが隠れているのを見つけ、驚く。,看護師がチョコレートを片手に持ち、フッと優しい笑顔になる。去っていくロボットの背中を見送る。,ロボットを擬人化しすぎず、あくまで「機械としての健気さ」を描くことで、人間と機械のちょうど良い距離感（ソーシャルロボティクス）を表現。
第2話　言葉なきコミュニケーション,緊迫した現場での、非言語的な状況伝達デザインの重要性。,ベテラン看護師（超多忙）、新人医師（焦っている）、ハコブくん,救急搬送が重なり、殺気立つナースステーション。新人医師が「あの薬、まだですか！？」と叫ぶ。,その背後からハコブくんが到着。しかし、いつもの「到着しました」という音声アナウンスは出さない。（空気を読んでいる）,その代わり、顔ディスプレイの色を「緊急を示す赤」ではなく、「落ち着きを促す深い青」でゆっくり点滅させ、静かにトレイを差し出す。,ベテラン看護師がそれに気づき、フッと息を吐く。「…ありがと、良いタイミングね」。医師も少し冷静さを取り戻す。,「状況に応じたモダリティ（音声のON/OFF）の切り替え」や「色彩心理を用いたアンビエントな情報伝達」といった、高度なインタラクションデザインの視点を表現。
第3話　「最短ルート」の罠,エンジニアリング的な効率性と、人間的な空間認識のズレ。,患者（松葉杖でリハビリ中）、ハコブくん,広い廊下で、患者が一生懸命松葉杖で歩行訓練をしている。,ハコブくんが向こうからやってくる。システム上の「最短ルート」は、患者のすぐ横をすり抜けるコース。,ハコブくんは減速せず、計算通り患者のギリギリ横を「シュンッ」と通過する。患者、驚いてバランスを崩しかける「うおっ！？」。,ハコブくんのディスプレイには「効率的搬送中（キリッ）」の表示。遠くで見ていた看護師長が「あとで設定見直しね…（怒）」と呟く。,技術的に正しい挙動が、必ずしも人間にとって快適ではないという「パーソナルスペース」や「心理的安全性」の課題を理解していることを示唆。
""", 'stack')

FILES = {
 'day3-ZeArA2HL': 'target', 'day3-tmB19lEB': 'hw', 'day39-jAoD9zMo': 'hw', 'day3-vuWqzByT': 'ui',
 'day4-Y4qhSa0d': 'screens', 'day5-Ti5Y0a1o': 'screens', 'day10-99rShwHn': 'screens',
 'day6-pBNtWWqI': 'face', 'day11-ZHEDulpe': 'shift', 'day38-iidr8BNd': 'hri',
 'day55-gmfRY92v': 'light', 'day17-YAH8yYE9': 'time', 'day9-vrBBzDi4': 'manga',
}
NOTE = {'manga': 'プロット表のうち、最初の3話だけを載せています。'}
for f, k in FILES.items():
    lab, data, mode = T[k]
    if mode == 'screens':
        open('%s/%s.html' % (OUT, f), 'w', encoding='utf-8').write(screens(lab, data)); print(f); continue
    nowrap = ()
    open('%s/%s.html' % (OUT, f), 'w', encoding='utf-8').write(page(lab, lab, data, mode, NOTE.get(k), nowrap))
    print(f)
