/* quiz.html only. The exam sheet is a tall paper panel (--bg) on the --ink ground: the open front folder of the
   home page made full size. Direction "The page is the object": real edges (perforated sides, notched top
   corners, a tear-off stub), filled shapes, no outlines, no shadows. css/site.css, js/site.js, js/motion.js and
   js/boot.js are shared and frozen; everything specific to the sheet lives here. */

.sheet-page {
  --pad-x: clamp(14px, 4vw, 64px);
  --num-w: clamp(2.25rem, 5vw, 3.75rem);
  --edge: 10px;
  padding: 0 clamp(12px, 3vw, 32px) clamp(64px, 10svh, 120px);
}

/* ---------- the paper ---------- */

/* The paper itself is not clipped (a clip-path would also cut the focus rings at its edges). Its sides are perforated with a dotted border of 10px round dots in the
   ground colour; its top corners are notched by two triangles of the ground laid over them. */
.paper {
  position: relative;
  max-width: 860px;
  margin: 0 auto;
  padding: clamp(32px, 6vw, 64px) var(--pad-x) clamp(32px, 5vw, 48px);
  border-inline: var(--edge) dotted var(--ink);
  background: var(--bg);
  color: var(--ink);
}

.paper::before,
.paper::after {
  content: "";
  position: absolute;
  top: 0;
  width: 28px;
  height: 28px;
  background: var(--ink);
  pointer-events: none;
}

.paper::before {
  left: calc(-1 * var(--edge));
  clip-path: polygon(0 0, 100% 0, 0 100%);
}

.paper::after {
  right: calc(-1 * var(--edge));
  clip-path: polygon(0 0, 100% 0, 100% 100%);
}

/* ---------- header: printed like the top of an exam ---------- */

.sheet-head {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(20px, 3.5vw, 36px);
  margin-bottom: clamp(48px, 7vw, 72px);
}

.sheet-page h1 {
  font-size: clamp(2rem, 4.9vw, 4.2rem);
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1.05;
}

/* 성명 · 범위 · 문항 · 예상 시간: a description list the way an exam prints its fields. */
.sheet-fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px 24px;
  margin: 0;
}

.sheet-fields .field {
  display: grid;
  align-content: start;
  gap: 6px;
  min-width: 0;
}

.sheet-fields .field--name {
  grid-column: 1 / -1;
}

.sheet-fields dt {
  font-size: 1rem;
  line-height: 1.4;
}

.sheet-fields dt label {
  font-weight: 600;
}

.sheet-fields dd {
  margin: 0;
  font-size: var(--step-lead);
  font-weight: 500;
  line-height: 1.3;
}

.sheet-fields select {
  width: 100%;
  min-height: var(--target);
  padding: 8px 16px;
  border: 0;
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  font-size: 1.125rem;
  font-weight: 400;
  cursor: pointer;
  transition: background-color var(--t-hover) ease;
}

.sheet-fields select:disabled {
  opacity: 1;
  cursor: default;
}

/* Quiet lines under the exam fields. The storage notice is a filled note on the paper: no outline, no shadow, no icon. */
.sheet-notes {
  display: grid;
  gap: 12px;
  min-width: 0;
}

.save-line {
  min-height: 1.5em;
  font-size: 1rem;
  line-height: 1.5;
}

#storage-notice {
  margin: 0;
  padding: 12px 18px;
  background: var(--ink);
  color: var(--bg);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.5;
}

/* ---------- questions: a real ordered list, the number is the native marker in the margin column ---------- */

/* The top padding is the room the first part strip hangs in (a margin on the first item would collapse into the gap above). */
#sheet {
  margin: 0;
  padding: 62px 0 0 var(--num-w);
}

#sheet > li.q {
  position: relative;
  margin: 0 0 clamp(48px, 7vw, 80px);
  padding-left: 8px;
}

#sheet > li.q::marker {
  font-size: clamp(1.375rem, 1rem + 1.4vw, 2.25rem);
  font-weight: 600;
  color: var(--ink);
}

/* A fieldset's baseline is its first option, so the marker would drift down to the choices.
   An empty zero-height line at the top of the item, sized like the prompt, pins the number to the prompt line. */
#sheet > li.q:not(.graded)::before {
  content: "\200b";
  display: block;
  height: 0;
  font-size: var(--step-lead);
  line-height: 1.4;
}

#sheet > li.q:last-child {
  margin-bottom: 0;
}

/* Where a part starts the exam prints it: a filled strip across the page, hung in the gap above the question. */
#sheet > li.q.part-start {
  margin-top: clamp(80px, 11vw, 120px);
}

/* The first strip hangs in the gap above the first question like the others, so the native number is never beside (or under) it. */
#sheet > li.q.part-start:first-child {
  margin-top: 0;
}

.part {
  position: absolute;
  left: calc(-1 * var(--num-w));
  right: 0;
  bottom: calc(100% + 18px);
  display: flex;
  align-items: center;
  min-height: 44px;
  margin: 0;
  padding: 6px 18px;
  background: var(--ink);
  color: var(--bg);
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.3;
}

.q-body {
  display: block;
}

.q-body > * + * {
  margin-top: 20px;
}

.q-body fieldset {
  display: block;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.q-body legend,
.q-body .q-prompt {
  display: block;
  padding: 0;
  margin: 0 0 16px;
  font-size: var(--step-lead);
  font-weight: 500;
  line-height: 1.4;
}

/* Choices: filled bars, the whole label is the target. The native radio covers it, invisible. */
.opts {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 10px;
}

.opt {
  position: relative;
  display: block;
}

.opt input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.opt span {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: var(--target);
  height: 100%;
  padding: 10px 18px;
  background: var(--surface);
  color: var(--ink);
  line-height: 1.45;
  transition: background-color var(--t-hover) ease, color var(--t-hover) ease, transform var(--t-press) var(--ease-out);
}

.opt span::before {
  content: "";
  flex: none;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--bg);
  transition: background-color var(--t-hover) ease;
}

@media (hover: hover) and (pointer: fine) {
  .opt:hover span {
    background: #dfe5e8;
  }

  .opt input:checked:hover + span {
    background: var(--ink);
  }

  .sheet-fields select:hover:not(:disabled) {
    background: #dfe5e8;
  }
}

.opt:active span {
  transform: scale(0.985);
}

.opt input:checked + span {
  background: var(--ink);
  color: var(--bg);
}

.opt input:checked + span::before {
  background: var(--bg);
}

.opt input:focus-visible + span {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
}

.opt input:disabled {
  cursor: default;
}

/* Short answer */
.q-body input[type="text"] {
  width: 100%;
  min-height: var(--target);
  padding: 10px 18px;
  border: 0;
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  font-size: 1.125rem;
  transition: background-color var(--t-hover) ease;
}

@media (hover: hover) and (pointer: fine) {
  .q-body input[type="text"]:hover:not(:disabled) {
    background: #dfe5e8;
  }
}

.q-body input[type="text"]:disabled {
  opacity: 1;
  color: var(--ink);
}

.q-body input[type="text"]::placeholder {
  color: var(--muted);
  opacity: 1;
}

/* Code: verbatim, monospace only here, scrolls inside its own block so the page never scrolls sideways. */
pre.code {
  margin: 0;
  padding: 18px 22px;
  overflow-x: auto;
  background: var(--surface);
  color: var(--ink);
  font-size: 0.9375rem;
  line-height: 1.7;
  white-space: pre;
  tab-size: 4;
}

pre.code:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
}

pre.code code {
  font: inherit;
}

/* ---------- the stub: a tear-off strip of the same paper, perforated along its top ---------- */

.submit-block {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px 28px;
  margin-top: clamp(56px, 8vw, 96px);
  padding: 30px clamp(18px, 3vw, 32px) 28px;
  border-top: 10px dotted var(--ink);
  background: var(--surface);
}

.stub-text {
  display: grid;
  flex: 1 1 15rem;
  gap: 4px;
  order: 2;
}

.submit-block .button {
  order: 1;
}

#practice-link {
  text-decoration: none;
}

.stub-note {
  font-size: 1.0625rem;
  line-height: 1.5;
}

#status {
  min-height: 1.6em;
  line-height: 1.5;
}

@media (max-width: 599px) {
  .submit-block .button {
    width: 100%;
  }
}

/* ---------- the confirmation and the PIN slip: paper slips laid on the dark ground, same perforated sides as the sheet ---------- */

.slip-dialog {
  width: min(34rem, calc(100vw - 32px));
  max-width: none;
  padding: clamp(24px, 5vw, 40px) clamp(20px, 4vw, 36px);
  border: 0;
  border-inline: var(--edge, 10px) dotted var(--ink);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--ink);
}

.slip-dialog::backdrop {
  background: rgb(31 48 56 / 0.86);
}

.slip-dialog h2 {
  font-size: var(--step-head);
}

#confirm-desc,
.slip-desc {
  margin-top: 16px;
  font-size: var(--step-body);
  line-height: 1.55;
}

#blank-count {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.confirm-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 16px;
  margin-top: clamp(24px, 4vw, 32px);
}

.confirm-actions .button {
  flex: 1 1 12rem;
}

/* Same shape as the one button; only the fill steps down so the least destructive control is not the accent. */
.button--quiet {
  background: var(--surface);
  color: var(--ink);
}

@media (hover: hover) and (pointer: fine) {
  .button--quiet:hover {
    background-color: #dfe5e8;
  }
}

.button--quiet:focus-visible {
  outline-color: var(--accent);
}

@media (prefers-reduced-motion: no-preference) {
  .slip-dialog[open] {
    animation: slip-in var(--t-ui) var(--ease-out);
  }

  .slip-dialog[open]::backdrop {
    animation: slip-fade var(--t-ui) ease-out;
  }
}

@keyframes slip-in {
  from {
    opacity: 0;
    transform: translateY(16px);
  }
}

@keyframes slip-fade {
  from {
    opacity: 0;
  }
}

/* ---------- graded in place: the sheet becomes a marked exam ---------- */

/* Score summary: a filled ink block at the top of the paper. */
#score {
  position: relative;
  margin-bottom: clamp(36px, 5vw, 48px);
  padding: clamp(24px, 4vw, 44px);
  background: var(--ink);
  color: var(--bg);
}

#score h2 {
  font-size: var(--step-head);
}

#score .score-line {
  margin-top: 20px;
  font-size: var(--step-lead);
  line-height: 1.3;
}

#score .score-line [data-score] {
  margin-inline: 0.1em;
  font-size: clamp(4.5rem, 14vw, 7.5rem);
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 0.9;
}

#score .score-figures {
  display: flex;
  flex-wrap: wrap;
  gap: 12px clamp(28px, 5vw, 56px);
  margin-top: clamp(20px, 3vw, 32px);
}

#score .score-figure {
  display: flex;
  align-items: baseline;
  gap: 12px;
  font-size: var(--step-lead);
  line-height: 1.2;
}

#score .score-figure [data-score] {
  font-size: var(--step-head);
  font-weight: 500;
  letter-spacing: -0.02em;
}

#score .score-of {
  font-size: var(--step-lead);
}

#score .attempt-member {
  margin-top: clamp(20px, 3vw, 28px);
  font-size: 1.0625rem;
  line-height: 1.5;
}

#score [data-score],
.score-of {
  font-variant-numeric: tabular-nums;
}

/* Focus lands here programmatically after grading; the heading is not a control, so no ring. */
#score-heading:focus {
  outline: none;
}

/* The result block: a filled note on the paper above its question. The mark sits in the margin column under the number. */
.q-result {
  position: relative;
  display: grid;
  gap: 8px;
  padding: clamp(16px, 3vw, 24px) clamp(16px, 3vw, 28px);
  background: var(--surface);
  color: var(--ink);
  font-size: 1.0625rem;
  line-height: 1.55;
}

/* The question follows its code block with a clear gap (the fieldset and prompt margins would otherwise win over the list rule). */
.q-body > pre.code + * {
  margin-top: 24px;
}

.q-body > .q-result + * {
  margin-top: clamp(24px, 4vw, 32px);
}

.q-result .verdict {
  font-size: var(--step-lead);
  font-weight: 600;
  line-height: 1.3;
}

.q-result .r-line {
  min-width: 0;
}

.q-result .r-label {
  font-weight: 600;
}

.q-result .explain {
  display: grid;
  gap: 4px;
  margin-top: 6px;
}

.q-result .explain + .r-line {
  margin-top: 10px;
}

/* Marks, drawn in CSS: a filled circle for 정답, a slash for 오답. The word beside them says it too. */
.q-result .mark {
  position: absolute;
  top: clamp(3.25rem, 4.2vw + 1.4rem, 4.25rem);
  left: calc(-8px - (var(--num-w) + 28px) / 2);
  width: 28px;
  height: 28px;
}

.q-result[data-result="correct"] .mark::before {
  content: "";
  position: absolute;
  inset: 2px;
  border-radius: 50%;
  background: var(--accent);
}

.q-result[data-result="wrong"] .mark::before {
  content: "";
  position: absolute;
  left: 11px;
  top: -2px;
  width: 6px;
  height: 32px;
  background: var(--ink);
  transform: rotate(35deg);
}

/* Choices in the graded sheet: the correct one carries a ring-circle, the member's wrong pick a slash cut into its dot. */
.opt.is-correct span {
  font-weight: 600;
}

.opt.is-correct span::before {
  background: var(--bg);
  border: 6px solid var(--accent);
}

.opt.is-wrong span::before {
  border-radius: 0;
  background: var(--bg);
  clip-path: polygon(62% 0, 100% 0, 38% 100%, 0 100%);
}

.opt input:disabled + span {
  cursor: default;
}

/* Tablet and up: four short choices sit two by two. */
@media (min-width: 720px) {
  .sheet-fields {
    grid-template-columns: repeat(3, max-content);
    justify-content: start;
    column-gap: clamp(32px, 5vw, 56px);
  }

  .opts--grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Wide screens: the paper keeps a readable exam width on the ink ground. */
@media (min-width: 1200px) {
  .paper {
    max-width: 860px;
  }

  .sheet-page {
    padding-bottom: clamp(96px, 14svh, 160px);
  }
}

/* ---------- motion: the sheet comes in once; every control answers the finger ---------- */

@media (prefers-reduced-motion: no-preference) {
  /* Below-the-fold parts show themselves after a while even if the script never runs. */
  .js [data-reveal]:not(.is-in):not([data-reveal="load"]) {
    animation: reveal-failsafe 1ms linear 6s forwards;
  }

  /* Graded in place: each block rises as it enters, then its mark sets (opacity with a small scale, never from 0). */
  .js .q-result[data-reveal].is-in .mark {
    animation: mark-set 420ms var(--ease-out) backwards;
    animation-delay: calc(180ms + min(var(--i, 0), 14) * 80ms);
  }

}

@keyframes mark-set {
  from {
    opacity: 0;
    transform: scale(0.96);
  }
}

@media (prefers-reduced-motion: reduce) {
  .opt span,
  .opt span::before,
  .sheet-fields select,
  .q-body input[type="text"] {
    transition: none;
  }

  .opt:active span {
    transform: none;
  }
}

/* ---------- team records: the send line in the score block, the PIN slip, the team rate under a verdict ---------- */

.team-send {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px 28px;
  margin-top: clamp(20px, 3vw, 28px);
  padding-top: clamp(20px, 3vw, 28px);
  border-top: 10px dotted var(--bg);
}

.team-text {
  flex: 1 1 18rem;
  font-size: 1.0625rem;
  line-height: 1.5;
}

.team-send .text-link {
  color: var(--bg);
}

.pin-field {
  display: grid;
  gap: 8px;
  margin-top: 20px;
}

.pin-field label {
  font-size: 1rem;
  font-weight: 600;
}

.pin-input {
  width: 8ch;
  min-height: var(--target);
  padding: 8px 16px;
  border: 0;
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--step-lead);
  letter-spacing: 0.3em;
  font-variant-numeric: tabular-nums;
}

.pin-error {
  min-height: 1.5em;
  margin-top: 12px;
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.5;
}

.q-result .team-rate[data-low="true"] {
  font-weight: 600;
}

.q-result .team-rate[data-low="true"] .r-label {
  padding: 0 6px;
  background: var(--ink);
  color: var(--bg);
}

/* ---------- 내 오답 노트: the same paper, one section per week, each wrong question a note ---------- */

.notes-lead {
  max-width: 40ch;
  font-size: var(--step-body);
  line-height: 1.55;
}

.notes-open {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  gap: 16px 24px;
}

.notes-field {
  display: grid;
  flex: 0 1 16rem;
  gap: 6px;
}

.notes-field label {
  font-size: 1rem;
  font-weight: 600;
}

.notes-field select {
  min-height: var(--target);
  padding: 8px 16px;
  border: 0;
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  font-size: 1.125rem;
  cursor: pointer;
}

.notes-status {
  flex: 1 1 100%;
  min-height: 1.5em;
  font-size: 1rem;
  line-height: 1.5;
}

.note-owner {
  margin-bottom: clamp(24px, 4vw, 40px);
  padding: 14px 20px;
  background: var(--ink);
  color: var(--bg);
  font-weight: 600;
}

.note-week + .note-week,
.team-low {
  margin-top: clamp(48px, 7vw, 72px);
}

.note-week h2,
.team-low h2 {
  font-size: clamp(1.6rem, 1.2rem + 1.6vw, 2.4rem);
}

.note-score,
.team-low-note {
  margin-top: 10px;
  font-size: 1.0625rem;
  line-height: 1.5;
}

.note-score .nums {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.note-list {
  display: grid;
  gap: 12px;
  margin: 24px 0 0;
  padding: 0;
  list-style: none;
}

.note {
  display: grid;
  gap: 8px;
  padding: 18px 20px 20px;
  background: var(--surface);
}

.note-meta,
.note-rate {
  font-size: 1rem;
  line-height: 1.45;
}

.note-rate {
  font-weight: 600;
}

.note-prompt {
  font-size: var(--step-body);
  line-height: 1.55;
}

.note-num {
  font-weight: 600;
}

.note-again {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

.note-empty {
  margin-top: 16px;
  font-size: 1.0625rem;
  line-height: 1.5;
}

/* Before a notebook is opened: what the page does, in three filled rows. */
.note-guide {
  display: grid;
  gap: 12px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.note-guide li {
  display: grid;
  grid-template-columns: minmax(0, 12rem) minmax(0, 1fr);
  gap: 8px 24px;
  align-items: baseline;
  padding: 20px 24px;
  background: var(--surface);
}

.note-guide h2 {
  font-size: var(--step-lead);
  font-weight: 600;
}

.note-guide p {
  font-size: 1.0625rem;
  line-height: 1.55;
}

@media (max-width: 599px) {
  .note-guide li {
    grid-template-columns: minmax(0, 1fr);
  }
}
