:root { --bg: #f5f6f8; --panel: #ffffff; --border: #d8dce3; --text: #1f2430; --muted: #6b7280; --ok: #15803d; --ok-bg: #dcfce7; --fail: #b91c1c; --fail-bg: #fee2e2; --err: #b45309; --err-bg: #fef3c7; --idle: #6b7280; --idle-bg: #eceef2; --accent: #1d4ed8; } * { box-sizing: border-box; } body { margin: 0; padding: 20px; background: var(--bg); color: var(--text); font-family: "Malgun Gothic", "맑은 고딕", Segoe UI, sans-serif; font-size: 14px; } h1 { font-size: 19px; margin: 0 0 4px; } .sub { color: var(--muted); font-size: 12px; margin-bottom: 16px; } .panel { background: var(--panel); border: 1px solid var(--border); border-radius: 6px; padding: 14px 16px; margin-bottom: 14px; } .panel h2 { font-size: 13px; margin: 0 0 10px; color: var(--muted); font-weight: 600; letter-spacing: .3px; } .banner { padding: 12px 16px; border-radius: 6px; margin-bottom: 14px; background: var(--fail-bg); color: var(--fail); border: 1px solid #fca5a5; } .banner.warn { background: var(--err-bg); color: var(--err); border-color: #fcd34d; } .banner code { background: rgba(0,0,0,.06); padding: 1px 5px; border-radius: 3px; } .var-group-select { display: flex; align-items: center; gap: 8px; margin: 0 0 12px; } .var-group-select label { font-size: 12px; color: var(--muted); } .vars { display: flex; flex-wrap: wrap; gap: 12px; } .var { display: flex; flex-direction: column; gap: 4px; min-width: 260px; flex: 1 1 260px; } .var label { font-size: 12px; color: var(--muted); } input[type=text], input[type=password] { padding: 7px 9px; border: 1px solid var(--border); border-radius: 4px; font-family: Consolas, monospace; font-size: 13px; background: #fff; color: var(--text); } input:focus { outline: 2px solid #bfdbfe; border-color: var(--accent); } .toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; } button { padding: 7px 14px; border: 1px solid var(--border); border-radius: 4px; background: #fff; color: var(--text); cursor: pointer; font-size: 13px; } button:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); } select { padding: 7px 9px; border: 1px solid var(--border); border-radius: 4px; background: #fff; color: var(--text); font-size: 13px; font-family: Consolas, monospace; max-width: 260px; } select:disabled { opacity: .5; } button:disabled { opacity: .5; cursor: not-allowed; } button.primary { background: var(--accent); border-color: var(--accent); color: #fff; } button.primary:hover:not(:disabled) { background: #1e40af; color: #fff; } .summary { display: flex; gap: 8px; margin-left: auto; flex-wrap: wrap; } .chip { padding: 4px 11px; border-radius: 12px; font-size: 12px; font-weight: 600; background: var(--idle-bg); color: var(--idle); } .chip.ok { background: var(--ok-bg); color: var(--ok); } .chip.fail { background: var(--fail-bg); color: var(--fail); } .chip.err { background: var(--err-bg); color: var(--err); } table.list { width: 100%; border-collapse: collapse; } table.list th { text-align: left; font-size: 12px; color: var(--muted); font-weight: 600; padding: 8px 10px; border-bottom: 1px solid var(--border); } table.list td { padding: 9px 10px; border-bottom: 1px solid #eef0f4; vertical-align: middle; } tr.api-row:hover { background: #fafbfc; } tr.group-row td { background: #eef1f6; border-bottom: 1px solid var(--border); padding: 8px 10px; } .group-head { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; } .group-head .gname { font-weight: 700; font-size: 13px; } .group-head .gmeta { color: var(--muted); font-size: 11px; font-family: Consolas, monospace; } .group-head .spacer { flex: 1 1 auto; } td.api-name { padding-left: 26px; } /* Generated per-group sequence number, not part of the API's own JSON, so it is deliberately muted/italic to read as chrome rather than data. */ td.seq { font-style: italic; color: var(--muted); font-size: 12px; text-align: right; } .method { font-family: Consolas, monospace; font-size: 12px; font-weight: 700; color: var(--accent); } .path { font-family: Consolas, monospace; font-size: 12px; color: var(--muted); word-break: break-all; } .badge { display: inline-block; min-width: 62px; text-align: center; padding: 3px 10px; border-radius: 4px; font-size: 12px; font-weight: 700; background: var(--idle-bg); color: var(--idle); } .badge.OK { background: var(--ok-bg); color: var(--ok); } .badge.Fail { background: var(--fail-bg); color: var(--fail); } .badge.ERROR { background: var(--err-bg); color: var(--err); } .badge.RUN { background: #dbeafe; color: var(--accent); } .note { font-size: 11px; color: var(--err); margin-top: 3px; } .detail { background: #fbfcfd; } .detail-inner { padding: 4px 10px 16px; } .cols { display: flex; gap: 14px; align-items: stretch; } .col { flex: 1 1 0; min-width: 0; border: 1px solid var(--border); border-radius: 5px; background: #fff; } .col > header { padding: 8px 11px; border-bottom: 1px solid var(--border); font-size: 12px; font-weight: 700; display: flex; gap: 10px; align-items: baseline; } .col .meta { font-weight: 400; color: var(--muted); font-family: Consolas, monospace; } .section-title { font-size: 11px; color: var(--muted); font-weight: 600; padding: 8px 11px 3px; } pre { margin: 0 11px 11px; padding: 9px; background: #f7f8fa; border: 1px solid #e6e9ee; border-radius: 4px; font-family: Consolas, monospace; font-size: 12px; line-height: 1.5; white-space: pre-wrap; word-break: break-all; max-height: 320px; overflow: auto; } .body-box { position: relative; } .copy-body-btn { position: absolute; top: 4px; right: 15px; z-index: 1; padding: 3px 9px; border: 1px solid var(--border); border-radius: 4px; background: #fff; color: var(--text); font-size: 11px; cursor: pointer; opacity: 0; transition: opacity .12s ease-in-out; } .body-box:hover .copy-body-btn, .copy-body-btn:focus { opacity: 1; } .copy-body-btn:disabled { cursor: default; } table.hdr { width: calc(100% - 22px); margin: 0 11px 11px; border-collapse: collapse; font-family: Consolas, monospace; font-size: 12px; } table.hdr td { padding: 3px 6px; border-bottom: 1px solid #f0f2f5; vertical-align: top; word-break: break-all; } table.hdr td.k { color: var(--muted); width: 34%; } table.hdr tr.differs td.k { color: var(--err); } table.hdr tr.differs td.v { background: #fffbeb; } .diff { margin-top: 14px; border: 1px solid var(--border); border-radius: 5px; background: #fff; } .diff > header { padding: 8px 11px; border-bottom: 1px solid var(--border); font-size: 12px; font-weight: 700; } .diff pre { margin: 0; border: 0; border-radius: 0; background: #fff; max-height: 420px; } .dl { display: block; padding: 0 6px; } .dl.del { background: var(--fail-bg); color: #7f1d1d; } .dl.add { background: var(--ok-bg); color: #14532d; } .dl.gap { color: #9ca3af; background: #f7f8fa; } .req-line { font-family: Consolas, monospace; font-size: 11px; color: var(--muted); padding: 0 11px 8px; word-break: break-all; } .imgbox { margin: 0 11px 11px; padding: 9px; border: 1px solid #e6e9ee; border-radius: 4px; max-height: 360px; overflow: auto; text-align: center; /* checkerboard so transparent PNGs stay readable */ background-color: #f7f8fa; background-image: linear-gradient(45deg, #e9ecf1 25%, transparent 25%, transparent 75%, #e9ecf1 75%), linear-gradient(45deg, #e9ecf1 25%, transparent 25%, transparent 75%, #e9ecf1 75%); background-size: 16px 16px; background-position: 0 0, 8px 8px; } .imgbox img { max-width: 100%; height: auto; vertical-align: middle; } /* Host column. A left/right mismatch is nearly always a config slip, so it gets the error colour rather than being easy to skim past. */ td.host { font-family: Consolas, "Courier New", monospace; font-size: 12px; word-break: break-all; } td.host.differs { color: #b42318; font-weight: 600; } /* Response headers that take part in the verdict. Distinct from .differs, which only means "the two sides differ" and carries no verdict weight. */ table.hdr tr.judged td.k { font-weight: 700; } table.hdr tr.judged td.k::after { content: " [판정]"; font-weight: 400; color: #5b6472; } table.hdr tr.judged.mismatch td.v { background: #fef3f2; color: #b42318; font-weight: 600; } .col header .expected-tag { color: #5b6472; font-weight: 400; } /* Mode indicator. compareMode is easy to miss buried in a sentence, so it gets its own always-visible, colour-coded chip: blue for a full two-sided comparison, amber for single-target (only one side is a live call, the other is a static expected value -- a meaningfully weaker check). */ .mode-line { display: flex; align-items: center; gap: 9px; margin: -2px 0 14px; flex-wrap: wrap; } .mode-chip { display: inline-flex; align-items: center; gap: 5px; padding: 4px 12px; border-radius: 12px; font-size: 12px; font-weight: 700; white-space: nowrap; } .mode-chip.dual { background: #dbeafe; color: var(--accent); } .mode-chip.single { background: var(--err-bg); color: var(--err); } .mode-target { font-size: 12px; color: var(--muted); font-family: Consolas, monospace; }