/* =========================================================================
   Apply page — searchable select component + dynamic grade/achievement rows
   ========================================================================= */


/* ---- Dynamic subject rows --------------------------------------------- */
.subject-row {
  display: grid; gap: 0.5rem; align-items: center;
  grid-template-columns: 1.4fr repeat(5, 1fr) auto;
}
.subject-row.mode-average { grid-template-columns: 2fr 1fr auto; }
.subject-row .form-control { padding: 0.5rem 0.6rem; }
.subject-row .col-head { font-size: 0.72rem; color: var(--muted); text-align: center; font-weight: 600; }

.subject-head { display: grid; gap: 0.5rem; grid-template-columns: 1.4fr repeat(5, 1fr) auto; }
.subject-head.mode-average { grid-template-columns: 2fr 1fr auto; }

.row-remove {
  border: none; background: var(--bad-wash); color: var(--bad-ink);
  width: 36px; height: 36px; border-radius: 10px; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background 0.15s ease;
}
.row-remove:hover { background: var(--bad-bg); }

@media (max-width: 768px) {
  /* Each subject becomes a small card: name on its own line, then the five
     semesters side by side. Stacking them was seven full-width rows per
     subject, which made a seven-subject rapor an endless scroll. */
  .subject-head { display: none; }
  .subject-row {
    position: relative;
    grid-template-columns: repeat(5, 1fr);
    gap: 0.35rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    padding: 0.7rem;
  }
  .subject-row .subj-name {
    grid-column: 1 / -1;
    padding-right: 2.6rem;          /* clear of the delete button */
    margin-bottom: 0.15rem;
  }
  /* Narrow boxes, so the value is centred and the S1–S5 placeholder does the
     labelling that the (hidden) header row used to do. */
  .subject-row .form-control {
    padding: 0.45rem 0.2rem;
    text-align: center;
    font-size: 0.9rem;
  }
  .subject-row .subj-name { text-align: left; font-size: 0.95rem; padding-left: 0.7rem; }
  .subject-row .row-remove {
    position: absolute; top: 0.55rem; right: 0.55rem;
    width: 32px; height: 32px;
  }
  .subject-row .col-head { display: block; text-align: left; }

  /* Average mode has one value, not five, so it keeps a simple two-up layout. */
  .subject-row.mode-average { grid-template-columns: 1fr; }
  .subject-row.mode-average .form-control { text-align: left; padding: 0.5rem 0.7rem; }
}

/* Very narrow phones: shave the gap so five boxes still fit without scrolling. */
@media (max-width: 360px) {
  .subject-row { gap: 0.25rem; padding: 0.6rem; }
  .subject-row .form-control { font-size: 0.82rem; padding: 0.4rem 0.1rem; }
}

/* ---- Achievement card -------------------------------------------------- */
.achievement-row {
  border: 1px solid var(--line); border-radius: var(--radius); padding: 1rem;
  position: relative;
}
.achievement-row .row-remove { position: absolute; top: 0.6rem; right: 0.6rem; }

/* --- v2 form extras --------------------------------------------------- */
.req { color: var(--bad-ink); font-weight: 700; }

#tkaInputs.is-disabled { opacity: 0.45; pointer-events: none; }

/* ---- Saved data ----------------------------------------------------------
   The panel at the top loads: saved biodata, and the inputs of earlier
   analyses. The bar under the analyse button saves. The panel costs one line
   when shut, and every row has one obvious action, "Pakai", with the ones
   that manage a biodata quieter beneath it. The two that cannot be undone,
   and loading over a half-typed form, ask first. */
.pf { margin-bottom: 1.25rem; }
.pf-drop {
  background: var(--surface, #fbf7f3);
  border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}
.pf-drop[open] { box-shadow: var(--shadow-md); }

.pf-trigger {
  display: flex; align-items: center; gap: .75rem;
  padding: .75rem 1rem; cursor: pointer; list-style: none;
}
.pf-trigger::-webkit-details-marker { display: none; }
.pf-trigger-ico {
  flex: 0 0 auto; width: 2.25rem; height: 2.25rem; border-radius: .75rem;
  display: grid; place-items: center;
  background: var(--primary-soft); color: var(--accent-ink); font-size: 1.05rem;
}
.pf-trigger-txt { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; line-height: 1.35; }
.pf-trigger-txt b { font-size: .95rem; font-weight: 800; color: var(--ink); }
.pf-trigger-txt span { font-size: .8rem; color: var(--muted); }
.pf-trigger:hover .pf-trigger-txt b { color: var(--accent-ink); }
.pf-caret { flex: 0 0 auto; color: var(--muted); font-size: .85rem; transition: transform .18s ease; }
.pf-drop[open] .pf-caret { transform: rotate(180deg); }

.pf-panel { padding: .1rem 1rem 1rem; border-top: 1px solid var(--line); }
.pf-panel > .pk-note { margin: .85rem 0 0; }
.pf-group { margin-top: .9rem; }
.pf-group[hidden] { display: none; }
.pf-group-h { margin: 0 0 .45rem; font-size: .8rem; font-weight: 800; color: var(--muted); }
.pf-list { display: grid; gap: .4rem; }

.pf-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .5rem;
  padding: .6rem .7rem .6rem .85rem;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--bg, #f2ede7);
}
/* The row's one real action: the whole top line is the link. */
.pf-open {
  flex: 1 1 100%; min-width: 0;
  display: flex; align-items: center; gap: .75rem;
  color: inherit; text-decoration: none;
}
.pf-open-t { flex: 1 1 auto; min-width: 0; display: grid; gap: .1rem; }
.pf-name, .pf-meta { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pf-name { font-weight: 700; font-size: .9rem; color: var(--ink); }
.pf-meta { font-size: .78rem; color: var(--muted); }
.pf-blank { font-style: italic; }
.pf-use {
  flex: 0 0 auto; padding: .3rem .8rem; border-radius: 999px;
  background: var(--primary-soft); color: var(--accent-ink-2);
  font-size: .78rem; font-weight: 800;
  transition: background-color .15s ease, color .15s ease;
}
.pf-open:hover .pf-name { color: var(--accent-ink); }
.pf-open:hover .pf-use, .pf-open:focus-visible .pf-use { background: var(--primary); color: #fff; }

.pf-form { display: contents; }
/* Managing a biodata, quieter than using it. Pulled left by its own padding
   so the words line up with the name above. */
.pf-acts { display: flex; flex-wrap: wrap; align-items: center; gap: .15rem; margin-left: -.45rem; }
/* display:flex outranks the UA rule for [hidden], so the buttons stayed on
   screen next to the confirmation that replaced them. */
.pf-acts[hidden] { display: none !important; }
.pf-act {
  border: 1px solid transparent; background: none; color: var(--muted);
  border-radius: .55rem; padding: .2rem .45rem;
  font-size: .76rem; font-weight: 700; line-height: 1.4; cursor: pointer; white-space: nowrap;
}
.pf-act:hover { background: var(--surface); border-color: var(--line); color: var(--ink); }
.pf-act--danger:hover { background: var(--bad-wash); border-color: #f5c2c7; color: var(--bad-ink); }
.pf-act--go { background: var(--primary); border-color: var(--primary); color: #fff; }
.pf-act--go:hover { background: var(--primary-dark); border-color: var(--primary-dark); color: #fff; }
/* Inside a question the answers are real buttons, the destructive one red. */
.pf-ask .pf-act { background: var(--surface); border-color: var(--line); }
.pf-ask .pf-act--go { background: var(--primary); border-color: var(--primary); color: #fff; }
.pf-ask .pf-act--danger { background: #be123c; border-color: var(--bad-ink); color: #fff; }

/* The rename field lives in the row's own form so it works with no scripting;
   profiles.js hides it until "Ganti nama" is pressed. */
.pf-rename {
  flex: 1 1 8rem; min-width: 0;
  border: 1px solid var(--line); border-radius: 999px;
  padding: .22rem .7rem; font-size: .82rem; font-weight: 600;
  color: var(--ink); background: var(--surface);
}
.pf-rename:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-soft); }
.pf-row.js-idle .pf-rename { display: none; }

/* One question, one answer, in the row itself. */
.pf-ask {
  flex-basis: 100%; display: flex; flex-wrap: wrap; align-items: center; gap: .4rem;
  font-size: .8rem; font-weight: 600; color: var(--ink);
}
.pf-ask span { flex: 1 1 8rem; min-width: 0; }

.pf-more { display: inline-block; margin-top: .55rem; font-size: .8rem; font-weight: 700; }

/* -- The save bar: under the analyse button, where the form was filled in -- */
.pf-savebar {
  padding: .9rem 1rem;
  border: 1.5px dashed var(--accent-line); border-radius: var(--radius);
  background: var(--surface-2);
}
.pf-savebar-t {
  display: flex; align-items: baseline; gap: .5rem; margin: 0 0 .65rem;
  font-size: .86rem; line-height: 1.45; color: var(--muted);
}
.pf-savebar-t i { color: var(--accent-ink); }
.pf-savebar-t b { color: var(--ink); }
.pf-savebar-do { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }
.pf-savebar-do > .btn { flex: 0 0 auto; }
.pf-save { display: flex; gap: .4rem; flex: 1 1 15rem; min-width: 0; }
.pf-save .form-control { flex: 1 1 auto; min-width: 0; padding: .4rem .75rem; font-size: .9rem; }
.pf-save .btn { flex: 0 0 auto; }
.pf-full { margin: .55rem 0 0; font-size: .8rem; color: var(--muted); }
.pf-full[hidden] { display: none; }
.pf-savebar > .pk-note { margin: .6rem 0 0; }

[data-profile-panel].is-busy, [data-profile-savebar].is-busy { opacity: .6; pointer-events: none; }

@keyframes pfIn { from { opacity: 0; transform: translateY(-3px); } to { opacity: 1; transform: translateY(0); } }
.pf-row.is-fresh { animation: pfIn .25s ease both; }
.pf-row.is-going { opacity: 0; transition: opacity .16s ease; }
@media (prefers-reduced-motion: reduce) {
  .pf-row.is-fresh { animation: none; }
  .pf-row.is-going { transition: none; }
  .pf-caret, .pf-use { transition: none; }
}

/* Below 16px, iOS zooms the whole page when a field takes focus. */
@media (pointer: coarse) {
  .pf-save .form-control, .pf-rename { font-size: 16px; }
}

.achievement-row .ss-trigger { width: 100%; }


/* ---- Autofill the grade table from a photograph -------------------------
   Sits above the table it fills, and looks like an offer rather than a field:
   a student who wants to type should be able to ignore it entirely. */
.rapor-shot {
  border: 1.5px dashed var(--line); border-radius: var(--radius);
  background: linear-gradient(180deg, rgba(37, 99, 235, .04), rgba(37, 99, 235, 0));
  padding: .95rem 1rem; margin-bottom: 1rem;
}
.rapor-shot-head { display: flex; align-items: center; gap: .8rem; flex-wrap: wrap; }
.rapor-shot-ico {
  flex: 0 0 auto; width: 38px; height: 38px; border-radius: 12px;
  background: var(--primary-soft); color: var(--accent-ink);
  display: grid; place-items: center; font-size: 1.05rem;
}
.rapor-shot-txt { flex: 1 1 12rem; min-width: 0; line-height: 1.4; }
.rapor-shot-txt b { display: block; font-size: .95rem; }
.rapor-shot-txt span { font-size: .82rem; color: var(--muted); }
.rapor-shot-head .btn { flex: 0 0 auto; }

.rapor-shot-hint {
  margin: .7rem 0 0; font-size: .78rem; color: var(--muted);
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
}
.rapor-shot-cost {
  display: inline-flex; align-items: center; gap: .25rem;
  padding: .15rem .5rem; border-radius: 999px;
  background: var(--warn-wash); color: var(--warn-ink); font-weight: 700;
}
.rapor-shot-cost i { font-size: .72rem; }

.rapor-shot-busy {
  display: flex; align-items: center; gap: .55rem;
  margin-top: .75rem; font-size: .85rem; font-weight: 600; color: var(--accent-ink);
}
.rapor-shot-busy[hidden] { display: none; }
.rapor-shot-spin {
  width: 1rem; height: 1rem; flex: 0 0 auto; border-radius: 50%;
  border: 2px solid var(--line); border-top-color: var(--primary);
  animation: raporSpin .7s linear infinite;
}
@keyframes raporSpin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .rapor-shot-spin { animation: none; } }

/* ---- What was read, before any of it is applied ---- */
.rapor-review { margin-top: .9rem; }
.rapor-review[hidden] { display: none; }
.rapor-review-say { margin: 0 0 .6rem; font-size: .82rem; color: var(--muted); line-height: 1.5; }
.rapor-review-say b { color: var(--ink); }

/* No max-height and no scrolling. A rapor holds fifteen subjects at the very
   most, and a scrolling sub-list inside a form is a box that swallows the
   wheel — the same trap the report cards were fixed for. It grows instead. */
.rapor-review-rows {
  display: flex; flex-direction: column; gap: .3rem;
  padding: .35rem; background: var(--surface, #fbf7f3);
  border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.rapor-row {
  display: flex; align-items: center; gap: .6rem;
  padding: .4rem .5rem; border-radius: var(--radius-sm);
  cursor: pointer; margin: 0;
}
.rapor-row:hover { background: var(--primary-soft); }
.rapor-row-name {
  flex: 1 1 auto; min-width: 0; font-size: .84rem; font-weight: 700;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rapor-row-cells { flex: 0 0 auto; display: flex; gap: .25rem; }
.rapor-cell {
  min-width: 2.1rem; padding: .12rem .3rem; border-radius: .4rem;
  background: var(--surface-2); color: var(--ink);
  font-size: .78rem; font-weight: 700; text-align: center;
  font-variant-numeric: tabular-nums;
}
/* A cell the model could not read stays visibly empty rather than guessed. */
.rapor-cell.is-blank { background: transparent; color: var(--muted); font-weight: 400; }

/* The scan merges into what is already there, so the review has to say which
   cells it touched. Three states, and the two that matter are the ones that
   change something the student typed. */
.rapor-cell.is-set { background: var(--primary-soft); color: var(--accent-ink); }
.rapor-cell.is-over {
  background: var(--warn-wash); color: var(--warn-ink);
  box-shadow: inset 0 0 0 1px #f0c07a;
}
.rapor-row.is-new .rapor-row-name { color: var(--accent-ink); }
.rapor-row-tag {
  font-style: normal; margin-left: .35rem; padding: .05rem .35rem;
  border-radius: 999px; background: var(--primary-soft); color: var(--accent-ink);
  font-size: .62rem; font-weight: 800; letter-spacing: .04em; text-transform: uppercase;
  vertical-align: 1px;
}

/* Which semester the page was read as. SNBP counts S1-S5 straight through
   kelas 10 to 12, so a page headed "Kelas XI Semester 1" is S3 — the sum that
   used to go wrong. It is shown, and it is one dropdown to fix. */
.rapor-slot {
  display: flex; align-items: center; gap: .75rem; flex-wrap: wrap;
  margin: 0 0 .7rem; padding: .55rem .7rem;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface, #fbf7f3);
}
.rapor-slot[hidden] { display: none; }
.rapor-slot.is-unsure { border-color: #f0c07a; background: var(--warn-wash); }
.rapor-slot-txt { flex: 1 1 9rem; min-width: 0; display: flex; flex-direction: column; line-height: 1.35; }
.rapor-slot-txt span { font-size: .7rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.rapor-slot-txt b { font-size: .84rem; }
.rapor-slot-pick { flex: 0 0 auto; display: flex; align-items: center; gap: .4rem; }
.rapor-slot-lbl { font-size: .78rem; color: var(--muted); white-space: nowrap; }
.rapor-ss { min-width: 13rem; }
.rapor-ss .ss-trigger { padding: .35rem .7rem; font-size: .8rem; }
.rapor-slot.is-busy { opacity: .6; pointer-events: none; }

/* What the two cell colours mean. Shown only when a scan actually produced
   one of them, because a legend for nothing is just more to read. */
.rapor-legend {
  display: flex; flex-wrap: wrap; gap: .25rem .9rem; margin: .5rem 0 0;
  font-size: .72rem; color: var(--muted);
}
.rapor-legend[hidden] { display: none; }
.rapor-legend span { display: inline-flex; align-items: center; gap: .3rem; }
.rapor-key { width: .8rem; height: .8rem; border-radius: .25rem; display: inline-block; }
.rapor-key--set { background: var(--primary-soft); box-shadow: inset 0 0 0 1px #bcd4ff; }
.rapor-key--over { background: var(--warn-wash); box-shadow: inset 0 0 0 1px #f0c07a; }

.rapor-keep {
  display: flex; align-items: center; gap: .45rem; margin: 0 0 .6rem;
  font-size: .8rem; color: var(--ink); cursor: pointer;
}
.rapor-keep[hidden] { display: none; }

@media (max-width: 575px) {
  .rapor-row { flex-wrap: wrap; }
  .rapor-row-name { flex: 1 1 100%; }
  .rapor-row-cells { padding-left: 1.6rem; }
  .rapor-slot-pick { flex: 1 1 100%; }
  .rapor-ss { flex: 1 1 auto; min-width: 0; }
}

/* ---- The wait (reworked 17 Oct 2026) --------------------------------------
   One card on the page's own surface. While it works its edge carries a
   turning blue line (the "subscribe" outline) with a faint glow under it.
   Inside, a picture per step (the grades read off the rapor, the crowd with
   the student in it, a meter searching for their chance, the explanation
   being written), a list ticking the steps off, and a bar. Sized in em off
   the card's own font size, so the landing page's film can play the same
   card at the size of a phone screen. assets/js/an-loader.js drives it. */
@property --an-a { syntax: '<angle>'; inherits: false; initial-value: 0deg; }

.an-wait {
  position: relative; isolation: isolate;
  border-radius: var(--radius-xl);
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--ink); text-align: center;
  padding: 2em 1.4em 1.6em;
  font-size: 1.05rem;
  max-width: 32rem;
  margin-inline: auto;
}
/* The turning line, drawn on the edge only (a ring: the gradient masked to
   the border box minus the padding box). */
.an-wait::before,
.an-wait::after {
  content: ""; position: absolute; inset: -1px; z-index: -1;
  border-radius: inherit;
  padding: 2px;
  background: conic-gradient(from var(--an-a), transparent 0deg 200deg, rgba(96, 165, 250, .55) 260deg, var(--primary) 320deg, #93c5fd 345deg, transparent 360deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  opacity: 0;
  transition: opacity .4s ease;
  pointer-events: none;
}
/* Its glow: the same line, blurred, faint, under the card. */
.an-wait::after { inset: -3px; padding: 4px; filter: blur(10px); z-index: -2; }
.an-wait.is-working::before { opacity: 1; animation: anRing 2.4s linear infinite; }
.an-wait.is-working::after { opacity: .45; animation: anRing 2.4s linear infinite; }
@keyframes anRing { to { --an-a: 360deg; } }

/* The pictures: one at a time, each easing in as its step starts. */
.an-stage { position: relative; width: min(17em, 100%); height: 9em; margin: 0 auto 1.5em; }
.an-layer {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  opacity: 0; transform: scale(.96) translateY(.4em);
  transition: opacity .45s ease, transform .55s cubic-bezier(.16, 1, .3, 1);
}
.an-wait[data-step="rapor"] .an-layer--rapor,
.an-wait[data-step="crowd"] .an-layer--crowd,
.an-wait[data-step="chance"] .an-layer--chance,
.an-wait[data-step="write"] .an-layer--write,
.an-wait[data-step="done"] .an-layer--done { opacity: 1; transform: none; }

/* 1 · the rapor: the student's grades, chip by chip, under a scan line. */
.an-sheet {
  position: relative;
  padding: .8em;
  border-radius: .9em;
  background: var(--surface-2);
  overflow: hidden; overflow: clip;
}
.an-chips { display: grid; grid-template-columns: repeat(5, 2.5em); gap: .4em; }
.an-chips i {
  display: grid; place-items: center;
  height: 1.7em;
  border-radius: .5em;
  background: var(--surface);
  font-style: normal; font-size: .85em; font-weight: 800; font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.an-wait[data-step="rapor"] .an-chips i { animation: anChip .4s cubic-bezier(.2, .9, .3, 1.2) both; animation-delay: calc(var(--k) * 90ms + 150ms); }
.an-scan {
  position: absolute; left: 0; right: 0; top: 0; height: 2px;
  background: linear-gradient(90deg, transparent, var(--primary), transparent);
  box-shadow: 0 0 12px 2px rgba(59, 130, 246, .45);
  opacity: 0;
}
.an-wait[data-step="rapor"] .an-scan { animation: anScan 1.4s ease-in-out infinite; }
@keyframes anChip { from { opacity: 0; transform: scale(.6); } to { opacity: 1; transform: none; } }
@keyframes anScan { 0% { opacity: 0; transform: translateY(0); } 15% { opacity: 1; } 85% { opacity: 1; } 100% { opacity: 0; transform: translateY(7.5em); } }

/* 2 · the crowd: the others arrive, the student is the blue one. */
.an-crowd { display: grid; grid-template-columns: repeat(10, .8em); gap: .65em .7em; }
.an-crowd i { width: .8em; height: .8em; border-radius: 50%; background: var(--line-strong); }
.an-crowd i.is-you { position: relative; background: var(--primary); }
.an-crowd i.is-you::after {
  content: ""; position: absolute; inset: -.35em;
  border-radius: 50%; border: 2px solid var(--primary);
  opacity: 0;
}
.an-wait[data-step="crowd"] .an-crowd i { animation: anChip .35s ease-out both; animation-delay: calc(var(--k) * 28ms); }
.an-wait[data-step="crowd"] .an-crowd i.is-you::after { animation: anPing 1.6s ease-out 1.1s infinite; }
@keyframes anPing { from { opacity: .9; transform: scale(.7); } to { opacity: 0; transform: scale(1.8); } }

/* 3 · the meter: the student's dot swings along it while the chance is worked out. */
.an-meter { position: relative; width: 13em; height: 7em; }
.an-meter svg { position: absolute; left: 0; bottom: 0; width: 100%; height: auto; overflow: visible; }
.an-meter-track { fill: none; stroke: var(--line-strong); stroke-width: 6; stroke-linecap: round; }
.an-meter-arm {
  position: absolute; left: 50%; bottom: .15em;
  width: 0; height: 5.4em;
  transform-origin: 50% 100%;
  transform: rotate(-70deg);
}
.an-meter-arm i {
  position: absolute; left: -.7em; top: -.7em;
  width: 1.4em; height: 1.4em;
  border-radius: 50%;
  background: var(--primary);
  border: .25em solid var(--surface);
  box-shadow: 0 0 14px 2px rgba(59, 130, 246, .5);
}
.an-wait[data-step="chance"] .an-meter-arm { animation: anSweep 1.5s ease-in-out infinite alternate; }
@keyframes anSweep { from { transform: rotate(-70deg); } to { transform: rotate(70deg); } }

/* 4 · the explanation, written line by line. */
.an-doc { display: grid; gap: .7em; width: 14em; padding: 1em 1.1em; border-radius: .9em; background: var(--surface-2); }
.an-doc i {
  display: block; height: .7em; border-radius: .4em;
  background: linear-gradient(90deg, var(--line-strong) 0%, color-mix(in srgb, var(--primary) 45%, var(--line-strong)) 50%, var(--line-strong) 100%) 0 0 / 200% 100%;
  transform-origin: 0 50%;
}
.an-doc i:nth-child(1) { width: 92%; }
.an-doc i:nth-child(2) { width: 76%; }
.an-doc i:nth-child(3) { width: 88%; }
.an-doc i:nth-child(4) { width: 52%; }
.an-wait[data-step="write"] .an-doc i { animation: anWrite 3.2s cubic-bezier(.4, 0, .2, 1) infinite, anShimmer 1.6s linear infinite; }
.an-wait[data-step="write"] .an-doc i:nth-child(2) { animation-delay: .5s, 0s; }
.an-wait[data-step="write"] .an-doc i:nth-child(3) { animation-delay: 1s, 0s; }
.an-wait[data-step="write"] .an-doc i:nth-child(4) { animation-delay: 1.5s, 0s; }
@keyframes anWrite { 0% { transform: scaleX(0); } 30%, 85% { transform: scaleX(1); } 100% { transform: scaleX(1); opacity: .4; } }
@keyframes anShimmer { to { background-position: -200% 0; } }

/* Done: the ring closes into a tick. */
.an-layer--done { gap: .6em; align-content: center; }
.an-layer--done b { font-size: 1.05em; font-weight: 800; }
.an-check { width: 3.6em; height: 3.6em; }
.an-check circle { fill: var(--primary); }
.an-check path { fill: none; stroke: #fff; stroke-width: 4; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 40; stroke-dashoffset: 40; }
.an-wait[data-step="done"] .an-check { animation: anChip .45s cubic-bezier(.2, .9, .3, 1.3) both; }
.an-wait[data-step="done"] .an-check path { animation: anDraw .4s ease-out .25s forwards; }
@keyframes anDraw { to { stroke-dashoffset: 0; } }

/* The steps, ticked off. */
.an-steps { list-style: none; display: grid; gap: .1em; width: fit-content; max-width: 100%; margin: 0 auto; padding: 0; text-align: left; }
.an-steps li {
  display: flex; align-items: center; gap: .7em;
  padding: .3em 0;
  font-size: .95em; font-weight: 600; color: var(--muted);
  transition: color .3s ease;
}
.an-steps li > span:last-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.an-tick {
  flex: none; position: relative;
  display: grid; place-items: center;
  width: 1.25em; height: 1.25em;
  border-radius: 50%;
  border: 2px solid var(--line-strong);
  transition: background-color .3s ease, border-color .3s ease;
}
.an-tick i { font-size: .8em; color: #fff; opacity: 0; transform: scale(.4); transition: opacity .25s ease, transform .35s cubic-bezier(.2, .9, .3, 1.4); }
.an-steps li.is-now { color: var(--ink); font-weight: 800; }
.an-steps li.is-now .an-tick { border-color: var(--primary); border-top-color: transparent; animation: anSpin .8s linear infinite; }
.an-steps li.is-done { color: var(--ink-2); }
.an-steps li.is-done .an-tick { background: var(--primary); border-color: var(--primary); }
.an-steps li.is-done .an-tick i { opacity: 1; transform: none; }
@keyframes anSpin { to { transform: rotate(360deg); } }

/* Fills toward, never to, the end until the job really is done: a sign of
   life, not a measurement. A light runs along it. */
.an-bar {
  position: relative; display: block;
  width: min(16em, 70%); height: 5px; margin: 1.3em auto 0;
  border-radius: 5px; background: var(--line); overflow: hidden; overflow: clip;
}
.an-bar i {
  position: relative; display: block; width: 100%; height: 100%;
  border-radius: inherit; background: var(--primary);
  transform-origin: 0 50%; transform: scaleX(0);
  transition: transform .8s cubic-bezier(.25, .8, .3, 1);
  overflow: hidden; overflow: clip;
}
.an-bar i::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .55), transparent);
  transform: translateX(-100%);
}
.an-wait.is-working .an-bar i::after { animation: anRun 1.6s ease-in-out infinite; }
@keyframes anRun { to { transform: translateX(100%); } }
.an-msg { margin: 1em auto 0; max-width: 28rem; font-size: .88em; font-weight: 600; line-height: 1.5; color: var(--ink-2); }
.an-msg:empty { display: none; }

@media (prefers-reduced-motion: reduce) {
  .an-wait.is-working::before, .an-wait.is-working::after,
  .an-wait .an-chips i, .an-wait .an-scan, .an-wait .an-crowd i, .an-wait .an-crowd i.is-you::after,
  .an-wait .an-meter-arm, .an-wait .an-doc i, .an-wait .an-check, .an-wait .an-check path,
  .an-steps li.is-now .an-tick, .an-wait.is-working .an-bar i::after { animation: none; }
  .an-check path { stroke-dashoffset: 0; }
  .an-layer { transition: none; }
}
/* A slow phone: the line on the edge stands still and does not glow. */
.pk-lite .an-wait.is-working::before { animation: none; }
.pk-lite .an-wait::after { display: none; }


/* =========================================================================
   The analysis form, v3 (14 Oct 2026)

   Five numbered steps on matte cards, and beside them on a laptop a rail
   that stays in view: how far each step is, the analyse button, saving. On a
   phone the rail is the end of the form and its step list is left out.
   Everything here is scoped to .af (the form) and its neighbours (.af-load,
   .af-note, .af-empty), because the landing page's film draws the old grade
   rows and photo row from the same classes and must keep looking like them.
   No accent on a card or a heading: cobalt is the button, the step on screen
   is lit the way the top bar lights the page you are on, a finished step
   turns its number into a green tick.
   ========================================================================= */
.af { --af-rail: 320px; --af-gap: 1.5rem; display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--af-gap); }
.af-main { display: grid; gap: 1rem; min-width: 0; }
@media (min-width: 992px) {
  .af { grid-template-columns: minmax(0, 1fr) var(--af-rail); align-items: start; }
  .af-load, .af-note { margin-right: calc(320px + 1.5rem); }
}
.af-load { margin-bottom: 1rem; }

.af-step {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.35rem 1.5rem 1.5rem; scroll-margin-top: 96px; min-width: 0;
}
@media (max-width: 575px) { .af-step { padding: 1.1rem 1rem 1.2rem; } }

.af-step-head {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center;
  column-gap: .75rem; row-gap: .2rem; margin-bottom: 1.15rem;
}
.af-step-head h2 { grid-column: 2; grid-row: 1; margin: 0; font-size: 1.08rem; font-weight: 800; letter-spacing: -0.01em; color: var(--ink); }
.af-step-note { grid-column: 2 / -1; margin: 0; font-size: .85rem; line-height: 1.5; color: var(--muted); }
.af-step-side { grid-column: 3; grid-row: 1; margin: 0; font-size: .88rem; }
@media (max-width: 575px) {
  .af-step-side { grid-column: 2 / -1; grid-row: auto; }
}

/* The step's number; a tick once the step is complete. */
.af-num {
  flex: 0 0 auto; width: 28px; height: 28px; border-radius: 50%;
  display: inline-grid; place-items: center;
  border: 1px solid var(--line-strong); color: var(--muted);
  font-size: .8rem; font-variant-numeric: tabular-nums; line-height: 1;
}
.af-num b { font-weight: 800; }
.af-num i { display: none; font-size: .9rem; }
.af-step.is-done .af-step-head .af-num,
.af-steps a.is-done .af-num { background: var(--ok-bg); border-color: transparent; color: var(--ok-ink); }
.af-step.is-done .af-step-head .af-num b,
.af-steps a.is-done .af-num b { display: none; }
.af-step.is-done .af-step-head .af-num i,
.af-steps a.is-done .af-num i { display: block; }

.af .form-label { font-size: .82rem; font-weight: 600; color: var(--ink-2); margin-bottom: .35rem; }
.af-check .form-check-label { font-size: .92rem; color: var(--ink-2); }
.af-check .form-check-label strong { color: var(--ink); }

/* Two picks, side by side on a laptop, each its kampus over its prodi. */
.af-picks { display: grid; gap: 1rem; }
@media (min-width: 768px) { .af-picks { grid-template-columns: 1fr 1fr; } }
.af-pick { display: grid; gap: .8rem; align-content: start; min-width: 0; }
.af-pick-h { margin: 0; font-size: .78rem; font-weight: 800; letter-spacing: .02em; color: var(--muted); }
.af-pick-f { min-width: 0; }
@media (min-width: 768px) {
  .af-pick + .af-pick { padding-left: 1rem; border-left: 1px solid var(--line); }
}
@media (max-width: 767px) {
  .af-pick + .af-pick { padding-top: 1rem; border-top: 1px solid var(--line); }
}

/* The photo offer: one quiet row above the table, not a dashed box. */
.af .rapor-shot {
  border: 1px solid var(--line); border-radius: calc(var(--radius) - 6px);
  background: var(--surface-2); padding: .8rem .9rem; margin-bottom: 1.1rem;
}
.af .rapor-shot-head { gap: .75rem; flex-wrap: nowrap; }
.af-shot-ico { flex: 0 0 auto; font-size: 1.3rem; color: var(--muted); }
.af .rapor-shot-txt b { font-size: .92rem; }
.af .rapor-shot-txt span { display: block; font-size: .8rem; color: var(--muted); }
.af .rapor-shot-cost { flex: 0 0 auto; font-size: .78rem; }
@media (max-width: 575px) {
  .af .rapor-shot-head { flex-wrap: wrap; }
  .af .rapor-shot-txt { flex-basis: calc(100% - 2.2rem); }
  .af .rapor-shot-cost { margin-left: 2.05rem; }
}
.af .rapor-shot-teaser { margin: 0 0 1rem; }

/* The grade table. A laptop has the header row, so the cells drop their
   S1 to S5 placeholders there; a phone keeps them, having no header. */
.af-grades { display: grid; gap: .45rem; }
.af .row-remove { background: transparent; color: var(--muted); }
.af .row-remove:hover, .af .row-remove:focus-visible { background: var(--bad-bg); color: var(--bad-ink); }
@media (min-width: 769px) {
  .af .subject-head { margin-bottom: .1rem; }
  .af .subject-head .col-head { font-size: .75rem; font-weight: 700; color: var(--muted); text-align: center; }
  .af .subject-head .col-head:first-child { text-align: left; padding-left: .2rem; }
  .af .subject-row .form-control { height: 42px; }
  .af .subject-row input[type="number"] { text-align: center; font-variant-numeric: tabular-nums; }
  .af .subject-row input[type="number"]::placeholder { color: transparent; }
}
@media (max-width: 768px) {
  .af .subject-row { background: var(--surface-2); border-color: transparent; }
}
.af-adds { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .9rem; }

/* TKA: with "Belum ada nilai TKA" the fields fold away. */
.af #tkaInputs.is-disabled { display: none; }
.af-tka-foot {
  display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center;
  gap: .5rem; font-size: .82rem; color: var(--muted);
}
.af-tka-foot .form-check-label { color: var(--ink-2); font-size: .9rem; }

/* Achievements and the note, one card, a hairline between. */
.af-sub + .af-sub { margin-top: 1.25rem; padding-top: 1.25rem; border-top: 1px solid var(--line); }
.af-sub-h { display: block; margin: 0 0 .65rem; font-size: .9rem; font-weight: 700; color: var(--ink); }
.af-sub-h span { margin-left: .35rem; font-size: .82rem; font-weight: 500; color: var(--muted); }
.af-achs { display: grid; gap: .75rem; margin-bottom: .75rem; }
.af-achs:empty { display: none; }
.af .achievement-row {
  background: var(--surface-2); border: 0; border-radius: calc(var(--radius) - 6px);
  padding: .85rem 3.4rem .85rem .85rem;
}
.af .achievement-row .row-remove { top: .85rem; right: .55rem; }

/* The rail. */
.af-rail { min-width: 0; }
@media (min-width: 992px) { .af-rail { position: sticky; top: 96px; } }
.af-rail-in { display: grid; gap: 1rem; }

.af-steps {
  list-style: none; margin: 0; padding: .45rem;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  display: grid; gap: 2px;
}
@media (max-width: 991px) { .af-steps { display: none; } }
.af-steps a {
  display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: .7rem; align-items: center;
  padding: .5rem .6rem; border-radius: 12px; color: var(--ink); text-decoration: none;
  transition: background-color .15s ease;
}
.af-steps a:hover { background: color-mix(in srgb, var(--ink) 5%, transparent); color: var(--ink); }
.af-steps a.is-here { background: var(--nav-lit); }
.af-steps a:focus-visible { outline: 3px solid rgba(37, 99, 235, 0.45); outline-offset: 1px; }
.af-steps .af-num { grid-row: span 2; }
.af-steps-t { font-size: .9rem; font-weight: 700; line-height: 1.3; }
.af-steps-s { grid-column: 2; font-size: .78rem; line-height: 1.35; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.af-steps-s:empty { display: none; }

.af-go { display: grid; gap: .55rem; }
.af-go #analyzeBtn { width: 100%; justify-content: center; }
.af-go .form-problems { margin: 0; }
.af-go-meta { margin: 0; text-align: center; font-size: .8rem; color: var(--muted); }

.af .af-save {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); padding: .85rem .9rem;
}
.af .af-save .pf-savebar-t { margin-bottom: .55rem; font-size: .84rem; }
.af .af-save .pf-save { flex-basis: 100%; }

/* Out of energy: the form is not drawn, this is. */
.af-empty {
  text-align: center; padding: 2.5rem 1.5rem;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
}
.af-empty h2 { margin: 0 0 1rem; font-size: 1.2rem; font-weight: 800; }
.af #addAchievementBtn[hidden] { display: none; }
