/* Styles that only progress, settings and the screens around them need. The shared system is in app.css; read docs/design.md first. */

/* ---- 1. Small things more than one of these screens uses ---- */

/* A title with one quiet link at the other end of the line. */
.page-head.head-row { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }
.head-row .btn { min-height: 2.6rem; flex: 0 0 auto; }

.card-head.pad { padding: 1.05rem 1.1rem 0; margin-bottom: .35rem; }
.progress .card-head .sub { flex: 0 0 auto; }

.empty.small { padding: 1.1rem 1rem 1.6rem; }
.empty.small .face { width: 3.6rem; height: 3.6rem; }

.bar.thin { height: .4rem; }
.bar.mistake > div { background: var(--coral); }

/* A fold that is only folded on a phone. Where there is room it is always open and reads as a card
   with a title. Browsers that cannot do this keep an ordinary fold, which still works. */
@media (min-width: 840px) {
    @supports selector(::details-content) {
        .fold.open-wide { border-radius: var(--r-card); }
        .fold.open-wide::details-content { content-visibility: visible; }
        .fold.open-wide > summary { min-height: 0; padding: 1.05rem 1.15rem .55rem; font-family: var(--display); line-height: 1.3; cursor: default; pointer-events: none; }
        .fold.open-wide > summary::after { display: none; }
        .fold.open-wide > .fold-body { padding: 0 1.15rem 1.15rem; }
    }
}

/* ---- 2. Charts ----
   One measure and one scale each. Marks are thin, the grid is a hairline, and every word on a chart
   is in ink: the colour of a mark is never the colour of its number. Ink is the colour of a
   series. The red pen is used only where what is counted is mistakes. */

.chart { --plot-h: 8.5rem; position: relative; }
.chart-plot { position: relative; height: var(--plot-h); }

.chart-x { display: flex; margin-top: .4rem; font-size: .78rem; line-height: 1.2; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.chart-x .now { color: var(--ink); font-weight: 700; }

/* What a point or a column is, shown when it is pointed at or tapped. */
.chart-tip {
    display: none;
    position: absolute;
    z-index: 3;
    left: 50%;
    bottom: calc(100% + 1.5rem);
    transform: translateX(-50%);
    align-items: baseline;
    gap: .45rem;
    padding: .3rem .6rem;
    border-radius: var(--r-small);
    background: var(--ink);
    color: var(--paper);
    font-family: var(--text);
    font-size: .8rem;
    font-weight: 600;
    line-height: 1.25;
    white-space: nowrap;
    pointer-events: none;
    box-shadow: var(--shadow);
}
.chart-tip b { font-weight: 800; font-variant-numeric: tabular-nums; }

/* A line */
.chart-line .chart-plot { margin: 1.3rem .55rem 0 2.1rem; }
.chart-line .chart-x { justify-content: space-between; margin-left: 2.1rem; margin-right: .2rem; }

.chart-grid { position: absolute; left: 0; right: 0; height: 0; border-top: 1px solid var(--line); }
.chart-tick { position: absolute; right: 100%; top: 0; transform: translateY(-50%); margin-right: .5rem; font-size: .78rem; line-height: 1; color: var(--ink-3); font-variant-numeric: tabular-nums; }

.chart-svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.chart-stroke { fill: none; stroke: var(--ink); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.chart-area { fill: var(--ink); opacity: .06; stroke: none; }

.chart-point { position: absolute; top: 0; bottom: 0; width: min(calc(100% / max(1, var(--n) - 1)), 4.5rem); transform: translateX(-50%); outline: none; -webkit-tap-highlight-color: transparent; }
.chart-point:hover::before, .chart-point:focus::before { content: ""; position: absolute; left: 50%; top: 0; bottom: 0; border-left: 1px solid var(--line-strong); }
.chart-dot { position: absolute; left: 50%; bottom: var(--y); width: .5rem; height: .5rem; margin: 0 0 -.25rem -.25rem; border-radius: 50%; background: var(--ink); box-shadow: 0 0 0 2px var(--paper); }
.chart-point.now .chart-dot { width: .68rem; height: .68rem; margin: 0 0 -.34rem -.34rem; }
.chart-point:hover .chart-dot, .chart-point:focus .chart-dot { box-shadow: 0 0 0 2px var(--paper), 0 0 0 .4rem color-mix(in srgb, var(--ink) 14%, transparent); }
.chart-point .chart-tip { bottom: calc(var(--y) + .85rem); }
.chart-point:hover .chart-tip, .chart-point:focus .chart-tip { display: inline-flex; }
.chart-point.at-start .chart-tip { transform: translateX(-.8rem); }
.chart-point.at-end .chart-tip { left: auto; right: 50%; transform: translateX(.8rem); }

/* The first and the last value, written beside their points on the side the line is not on. */
.chart-label { position: absolute; bottom: var(--y); margin-bottom: .6rem; padding: 0 .2rem; border-radius: 4px; background: var(--paper); font-family: var(--display); font-size: .95rem; font-weight: 800; line-height: 1.1; color: var(--ink); pointer-events: none; }
.chart-label.below { margin-bottom: -1.65rem; }
.chart-label.start { left: -.45rem; }
.chart-label.end { right: -.5rem; }

/* Columns */
.chart-cols .chart-plot { display: flex; align-items: stretch; padding-top: 1.45rem; border-bottom: 1px solid var(--line-strong); }
.chart-col { flex: 1 1 0; min-width: 0; position: relative; display: flex; align-items: flex-end; justify-content: center; border-radius: 8px 8px 0 0; outline: none; -webkit-tap-highlight-color: transparent; }
.chart-col:hover, .chart-col:focus { background: var(--sunken); }
.chart-bar { position: relative; width: min(1.3rem, 62%); min-height: 3px; border-radius: 4px 4px 0 0; background: var(--ink); }
.chart-cols.mistake .chart-bar { background: var(--coral); }
.chart-bar.none, .chart-cols.mistake .chart-bar.none { min-height: 0; background: none; }
.chart-val { position: absolute; left: 50%; bottom: 100%; transform: translateX(-50%); padding-bottom: .22rem; font-family: var(--display); font-size: .9rem; font-weight: 700; line-height: 1; color: var(--ink); font-variant-numeric: tabular-nums; }
.chart-bar.none .chart-val { color: var(--ink-3); }
.chart-col:hover .chart-tip, .chart-col:focus .chart-tip { display: inline-flex; }
.chart-col.at-start .chart-tip { left: 0; transform: none; }
.chart-col.at-end .chart-tip { left: auto; right: 0; transform: none; }
.chart-cols .chart-x span { flex: 1 1 0; min-width: 0; display: flex; justify-content: center; white-space: nowrap; }

.chart-card .card-head { margin-bottom: .35rem; }
.chart-note { margin-top: .75rem; }
.chart-note + .chart-note { margin-top: .2rem; }
.one-week { margin-top: .4rem; color: var(--ink-2); }
.one-week strong { font-family: var(--display); font-size: 1.85rem; font-weight: 800; color: var(--ink); margin-right: .2rem; }

/* Words by stage: a thin bar with no words on it, and under it each stage's own line, name and number. */
.stage-bar { height: .6rem; border-radius: 999px; overflow: hidden; }
.stage-part { border-radius: 0; min-width: 4px; }
.stage { container-type: inline-size; margin-bottom: 1.1rem; }
.stage-legend { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .15rem 1.1rem; margin-top: .55rem; }
.stage-key { gap: .4rem; }
.stage-key .stage-line { width: 2.1rem; height: .7rem; }
.stage-key strong { font-variant-numeric: tabular-nums; }
@container (min-width: 30rem) { .stage-legend { grid-template-columns: repeat(4, auto); justify-content: start; column-gap: 1.5rem; } }

/* A name, a thin bar and a number on one line, the bars lined up. */
.meter-row { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(2.5rem, 1fr) 2.7rem; align-items: center; gap: .75rem; padding: .42rem 0; line-height: 1.3; }
.meter-row .tag { justify-self: end; margin: 0; font-variant-numeric: tabular-nums; }
.meter-row.stacked { grid-template-columns: minmax(0, 1fr) auto; gap: .3rem .75rem; padding: .5rem 0; }
.meter-row.stacked .bar { grid-column: 1 / -1; }
.sound-letters { font-family: var(--letters); font-weight: 700; }

.read-row { display: flex; flex-wrap: wrap; justify-content: space-between; gap: .05rem 1rem; padding: .4rem 0; }
.read-row + .read-row { border-top: 1px solid var(--line); }

/* ---- 3. Progress ---- */

.progress > h2 { margin-top: 1.9rem; }
.progress .stats { margin-top: .8rem; }
.stat .was { display: block; margin-top: .25rem; font-size: .78rem; line-height: 1.25; color: var(--ink-3); }

.recap { display: grid; gap: .1rem; }

.progress .cols.alone { max-width: 26rem; margin: 0 auto; }
.card.early { display: flex; align-items: center; gap: 1rem; }
.card.early .face { width: 3.6rem; height: 3.6rem; flex: 0 0 auto; color: var(--ink); }
.card.early h3 { margin: 0; }

.goal:has(.plan) { padding-bottom: .45rem; }
.goal .plan { margin-top: .8rem; border-top: 1px solid var(--line); }
.goal .plan[open] { padding-bottom: .7rem; }
.plan-fields { display: grid; grid-template-columns: 1fr 1fr; align-items: end; gap: .75rem; margin: .2rem 0 .9rem; }
.plan-fields .lbl { font-size: .88rem; line-height: 1.3; }
.plan-note { margin-top: .5rem; text-align: center; }

.progress .row { padding-top: .7rem; padding-bottom: .7rem; }
.progress .row .bar { margin: .4rem 0 .3rem; }

/* The monthly check sits under the weekly line it belongs with. */
.chart-more { margin: 1.1rem 0 .5rem; padding-top: .9rem; border-top: 1px solid var(--line); }
.stats.checks { grid-template-columns: repeat(auto-fill, minmax(4.6rem, 1fr)); margin-top: 0; }
.stats.checks .stat { padding: .55rem .3rem .5rem; background: var(--sunken); border-color: transparent; }
.stats.checks .n { font-size: 1.45rem; }
.progress .notice.below { margin: .8rem 0 0; }

/* A tablet has room for two charts side by side before the laptop's line at 840. */
@media (min-width: 700px) {
    .progress .cols.halves, .progress .cols.thirds { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.1rem; }
    .progress .cols.halves > :last-child:nth-child(odd), .progress .cols.thirds > :last-child:nth-child(odd) { grid-column: 1 / -1; }
}

/* Three across once each of the three can be as wide as a phone. */
@media (min-width: 1320px) {
    .progress .cols.thirds:has(> :nth-child(3)) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .progress .cols.thirds:has(> :nth-child(3)) > :last-child:nth-child(odd) { grid-column: auto; }
}

/* ---- 4. Settings ----
   One piece of markup, two screens. On a phone every heading shows, with its folds under it.
   From 840 pixels the headings are a list that stays in view, and only the chosen one is laid out
   beside it, with its folds open. */

.settings .set-group > h2 { margin-top: 1.6rem; }
.settings .set-group:first-child > h2 { margin-top: 0; }
.set-log { margin-top: .5rem; }

.set-card { display: grid; gap: 1.25rem; }
.set-card .chips { padding: 0 0 .35rem; }
.set-field .input, .settings .size-row { max-width: 26rem; }
/* Three looks, three equal buttons, like the three text sizes under them. */
.look-chips { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .5rem; max-width: 26rem; }
.look-chips .chip { justify-content: center; padding: 0 .4rem; min-height: 2.9rem; border-radius: var(--r-control); }
.look-chips .icon { width: 1.15em; height: 1.15em; }

.set-note { margin-top: .45rem; }
.set-lead { margin-bottom: .65rem; }
.set-gap { margin-top: .4rem; }
.set-gap-lg { margin-top: .75rem; }
.set-part { margin-top: 1.2rem; padding-top: 1.1rem; border-top: 1px solid var(--line); }
.set-reply { margin: .7rem 0 0; }
.set-count { margin-bottom: .3rem; }
.set-sub-head { margin: 1.1rem 0 0; }
.set-install { margin-bottom: .5rem; }
@media (min-width: 600px) { .set-install { max-width: 22rem; } }

/* On or off, said with a dot as well as in words. */
.set-state { display: flex; align-items: center; gap: .5rem; margin-bottom: .65rem; font-weight: 700; }
.set-state i { width: .6rem; height: .6rem; border-radius: 50%; background: var(--green); flex: 0 0 auto; }

.btn.danger { color: var(--wrong); }
.btn-row.pair > .btn { flex: 1 1 0; padding: 0 .6rem; }

.model-row { display: flex; align-items: baseline; gap: .6rem; padding: .3rem 0; }
.model-row .tag { flex: 0 0 auto; min-width: 6.3rem; justify-content: center; margin: 0; }
.model-row .tag .icon { width: 1em; height: 1em; vertical-align: -.12em; }

.settings .fold-body .row { padding-left: 0; padding-right: 0; }

@media (min-width: 840px) {
    .set { display: grid; grid-template-columns: minmax(15rem, 19rem) minmax(0, 1fr); gap: 1.6rem; align-items: start; }
    .set-nav { position: sticky; top: 1.5rem; }
    .set-nav .row { padding: .8rem 1rem; }
    .set-nav .row.on { background: var(--sunken); }
    .set-nav .ttl, .set-nav .meta { display: block; }

    .set-body { max-width: 40rem; }
    .set-group { display: none; }
    .set-group.on { display: block; }
    .settings .set-group > h2 { margin-top: 0; font-size: 1.35rem; }
    .set-log { margin-top: 0; }
    .set-body .fold { margin-bottom: .8rem; }
    .set-body .btn-block { max-width: 19rem; }
    .set-body .btn-row.pair { max-width: 26rem; }

    @supports selector(::details-content) {
        .fold.untitled-wide > summary { display: none; }
        .fold.untitled-wide > .fold-body { padding-top: 1.15rem; }
    }
}

/* ---- 5. The access code, and an address with nothing behind it ----
   One small thing in the middle of the screen: the face, a line or a box, one button. */

.gate { display: grid; align-content: center; justify-items: center; min-height: calc(100dvh - var(--tabbar) - 3.5rem); }
@media (min-width: 600px) { .gate { min-height: calc(100dvh - 5rem); } }

.gate-box { width: 100%; max-width: 23rem; }
.gate-head { display: grid; justify-items: center; gap: .15rem; text-align: center; }
.gate-head .face { width: 5.5rem; height: 5.5rem; margin-bottom: .5rem; color: var(--ink); }
.gate-check { margin-top: .5rem; }
.gate-go { margin-top: 1rem; }

.gate .empty { padding: 0 0 2rem; }
.gate .empty h1 { margin-top: .2rem; color: var(--ink); }
.gate .empty .btn { margin-top: .8rem; min-width: 12rem; }

/* ---- 6. The small window that saves one word (quick.html) ----
   About 360 by 420: the mark, one box in the letters face, one red button. js/quick.js puts what
   happened in data-state on the body: the face's mouth and the colour of the line follow it. */

.quick main { max-width: 24rem; margin: 0 auto; padding: .9rem 1.1rem 1rem; }

.quick-brand { display: inline-flex; align-items: center; gap: .45rem; color: var(--ink); text-decoration: none; }
.quick-brand:hover { text-decoration: none; }
.quick-brand .wordmark { font-size: 1.6rem; }

.quick h1 { font-size: 1.25rem; margin: .5rem 0 .45rem; }

.quick-word { min-height: 3.3rem; font-family: var(--letters); font-size: 1.45rem; font-weight: 600; letter-spacing: .04em; text-align: center; }
.quick-word::placeholder { font-family: var(--text); font-size: 1.05rem; font-weight: 400; letter-spacing: 0; }
.quick #save { margin-top: .5rem; min-height: 3.1rem; }

/* The line that says what happened. It keeps its height when empty, so nothing jumps. */
.quick #note { display: flex; align-items: center; gap: .45rem; min-height: 2.6rem; margin-top: .55rem; padding: .35rem .8rem; border-radius: var(--r-control); font-size: .98rem; font-weight: 600; line-height: 1.3; color: var(--ink-2); }
.quick #note:empty { padding: 0; }
.quick[data-state="saved"] #note { background: var(--right-bg); color: var(--right); }
.quick[data-state="waiting"] #note { background: var(--yellow-soft); color: var(--ink); }
.quick[data-state="mistook"] #note { background: var(--wrong-bg); color: var(--wrong); }
.quick[data-state="asking"] #note { min-height: 0; padding: .1rem .1rem 0; color: var(--ink-2); }
.quick[data-state="saved"] #note::before {
    content: "";
    flex: 0 0 auto;
    width: 1.25rem;
    height: 1.25rem;
    background: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5' fill='none' stroke='%23000' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* "Did you mean": the likeliest first, in ink. The keys 1, 2 and 3 choose, so they are shown where there is a keyboard. */
.quick #picks { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .45rem; counter-reset: pick; }
.quick #picks:empty { display: none; }
.quick #picks button { display: inline-flex; align-items: center; gap: .4rem; min-height: 2.6rem; padding: 0 .8rem; border: 1.5px solid var(--line-strong); border-radius: 999px; background: var(--paper); color: var(--ink); font: inherit; font-family: var(--letters); font-weight: 600; cursor: pointer; counter-increment: pick; }
.quick #picks button:hover { background: var(--sunken); }
.quick #picks button[data-first] { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.quick #picks button:last-child { font-family: var(--text); font-weight: 700; color: var(--ink-2); }
@media (hover: hover) and (pointer: fine) {
    .quick #picks button:nth-child(-n+3)::before { content: counter(pick); display: inline-grid; place-items: center; min-width: 1.3rem; height: 1.3rem; margin-left: -.3rem; border-radius: 6px; border: 1px solid currentColor; font-family: var(--text); font-size: .72rem; font-weight: 700; opacity: .75; }
}

.quick nav { display: flex; gap: 1.3rem; margin-top: .35rem; }
.quick nav a { display: inline-flex; align-items: center; min-height: 2.75rem; font-size: .95rem; font-weight: 700; }
/* While a question is open the window is about the question, and it has to fit. */
.quick[data-state="asking"] nav { display: none; }

/* The name is the face, with four mouths. At rest, and when a word was not saved, it is the squiggle. */
.quick .wm-mouth path, .quick .wm-mouth circle { display: none; fill: none; stroke-width: 3.6; stroke-linecap: round; stroke-linejoin: round; }
.quick .wm-mouth .m-mistook { display: inline; stroke: var(--coral); }
.quick[data-state="saved"] .wm-mouth .m-mistook, .quick[data-state="waiting"] .wm-mouth .m-mistook, .quick[data-state="asking"] .wm-mouth .m-mistook { display: none; }
.quick[data-state="saved"] .wm-mouth .m-smile { display: inline; stroke: var(--green); animation: pop var(--t) var(--ease-spring) both; }
.quick[data-state="waiting"] .wm-mouth .m-steady { display: inline; stroke: var(--amber); }
.quick[data-state="asking"] .wm-mouth .m-listen { display: inline; stroke: var(--blue); }
.quick[data-state="mistook"] .quick-brand { animation: shake .4s ease-in-out both; }

/* What the window says arrives, it does not just appear. */
.quick[data-state="saved"] #note, .quick[data-state="waiting"] #note, .quick[data-state="mistook"] #note { animation: rise var(--t) var(--ease-out) both; }

/* While the word is on its way the squiggle writes itself beside "Saving", and the button waits. */
.quick[data-state="saving"] #note::before {
    content: "";
    flex: 0 0 auto;
    width: 1.9em;
    height: .62em;
    background: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 34 11'%3E%3Cpath d='M2 6q3.75-6 7.5 0t7.5 0 7.5 0 7.5 0' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 34 11'%3E%3Cpath d='M2 6q3.75-6 7.5 0t7.5 0 7.5 0 7.5 0' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round'/%3E%3C/svg%3E") center / 100% 100% no-repeat;
    animation: write-clip 1.3s ease-in-out infinite;
}
.quick[data-state="saving"] #note { padding: .35rem .2rem; }
.quick[data-state="saving"] #save { pointer-events: none; opacity: .8; }

/* A saved word is a seed in the soil: at the far end of the line a seed drops onto its soil.
   The seed and the soil are two drawings on one box, and only the seed's place is moved. */
@keyframes quick-seed {
    0% { background-position: center -.6rem, center calc(100% - .2rem); opacity: 0; }
    30% { opacity: 1; }
    70% { background-position: center calc(100% - .2rem), center calc(100% - .2rem); }
    100% { background-position: center calc(100% - .32rem), center calc(100% - .2rem); opacity: 1; }
}
.quick[data-state="saved"] #note::after {
    content: "";
    flex: 0 0 auto;
    width: 2rem;
    height: 1.7rem;
    margin: -.2rem -.1rem -.2rem auto;
    background:
        radial-gradient(ellipse closest-side, var(--coral) 92%, transparent) center calc(100% - .32rem) / .78rem .56rem no-repeat,
        linear-gradient(color-mix(in srgb, currentColor 40%, transparent), color-mix(in srgb, currentColor 40%, transparent)) center calc(100% - .2rem) / 100% 2px no-repeat;
    animation: quick-seed .7s var(--ease-out) .1s both;
}

/* The choices of "did you mean" arrive one after another. */
.quick #picks button { animation: pop var(--t) var(--ease-spring) backwards; transition: background var(--t-fast) ease, transform var(--t-fast) var(--ease-out); }
.quick #picks button:nth-child(2) { animation-delay: 50ms; }
.quick #picks button:nth-child(3) { animation-delay: 100ms; }
.quick #picks button:nth-child(n+4) { animation-delay: 150ms; }
.quick #picks button:active { transform: scale(.95); }

/* ---- 7. Saving a word is planting a seed ----
   The line that says a word was saved has soil beside it, and the seed drops into it. The tick
   draws itself once the seed has landed. */

.saved-line { display: flex; align-items: center; gap: .75rem; animation: rise var(--t) var(--ease-out) both; }
/* The drawing is mostly air above a seed, so it is drawn large and its empty top is let out of the line. */
.saved-line .sprout { width: 3rem; height: 3.75rem; margin: -1.75rem 0 -.3rem -.15rem; color: inherit; }
.saved-line .sprout .soil { stroke: color-mix(in srgb, currentColor 40%, transparent); }
.saved-line .draws path { animation-delay: .45s; }
.saved-line a { white-space: nowrap; }

/* A word the app will not take: the red pen goes through it where it was typed, and the box shakes its head once. */
.capture-card .input-answer.is-refused {
    text-decoration: line-through;
    text-decoration-color: var(--coral);
    text-decoration-thickness: .09em;
    border-color: var(--coral);
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--coral) 20%, transparent);
    animation: shake .4s ease-in-out both;
}

/* Rows that arrive one after another, and a new one that arrives on top of them. */
.arrive > li { animation: rise var(--t) var(--ease-out) both; animation-delay: calc(var(--i, 0) * 40ms); }
.word-row .sprout { width: 2rem; height: 2.5rem; margin: -.45rem 0 0; }

@media (min-width: 840px) {
    /* The box keeps its place beside what was saved. What the app says about a save lands under it. */
    .capture-main > .capture-card { order: 1; }
    .capture-main > .notice { order: 2; }
}

/* ---- 8. A word's own page ----
   The word's story is at the top: its plant, as far along as the word is, and the three steps of
   the name. In a narrow column the plant stands beside the steps, so a long word keeps the whole
   line. Where the column is wide enough it stands beside the word. The column is measured, not the
   window, because beside the list the column can be narrower than a phone. */

.word-view .page-head { container-type: inline-size; }
.word-top { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .5rem .75rem; align-items: end; }
.word-top .word-big { grid-column: 1 / -1; }
.word-top .sprout { grid-row: 2; grid-column: 1; width: 2.1rem; height: 2.6rem; }
.word-top .took-steps { grid-row: 2; grid-column: 2; align-self: center; }

@container (min-width: 24rem) {
    .word-top { column-gap: 1rem; row-gap: .55rem; }
    .word-top .sprout { grid-row: 1 / span 2; width: 3.6rem; height: 4.5rem; margin-bottom: .1rem; }
    .word-top .word-big { grid-column: 2; grid-row: 1; }
}

.word-view > .notice { animation: rise var(--t) var(--ease-out) both; }
.word-view .tag .icon { width: 1em; height: 1em; }
.skill-row .sprout { width: 1.7rem; height: 2.1rem; margin-top: -.3rem; }

/* When a word opens, the pen marks its mistakes once: red through what does not belong, then
   green under what was left out. The marks themselves are the ones the diff always had. */
@keyframes mark-in { from { color: inherit; background-color: transparent; box-shadow: inset 0 0 0 transparent; text-decoration-color: transparent; } }
.mistakes .d-extra { animation: mark-in var(--t-slow) ease-out .3s both; }
.mistakes .d-missing { animation: mark-in var(--t-slow) ease-out .6s both; }

/* ---- 9. Folds open smoothly ----
   A fold grows to the height of what is in it and its words rise into place. Browsers that cannot
   grow a fold still get the rise. A fold that is always open where there is room is left alone. */

.fold[open] > .fold-body { animation: rise var(--t) var(--ease-out) both; }

@supports selector(::details-content) and (interpolate-size: allow-keywords) {
    .fold, details.fold-inner { interpolate-size: allow-keywords; }

    /* Shut at once when closing, so nothing hangs out of a fold that is getting shorter. */
    .fold::details-content, details.fold-inner::details-content {
        block-size: 0;
        overflow: clip;
        transition: block-size var(--t) var(--ease-out), content-visibility var(--t) allow-discrete, overflow 0s allow-discrete;
    }

    /* Open: what is inside may reach outside again (a chart's label does) once the fold has grown. */
    .fold[open]::details-content, details.fold-inner[open]::details-content {
        block-size: auto;
        overflow: visible;
        transition: block-size var(--t) var(--ease-out), content-visibility var(--t) allow-discrete, overflow 0s var(--t) allow-discrete;
    }

    @media (min-width: 840px) {
        .fold.open-wide::details-content { block-size: auto; overflow: visible; transition: none; }
    }
}

/* ---- 10. Your words, as a list or as a garden ----
   A small switch beside the count. The garden is every loaded word as a plant with its word under
   it; the plant whose word is open is ringed in ink, the way an open row is marked in the list. */

.words-head { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: .3rem .75rem; margin-top: .15rem; }
.words-head .sub { margin: 0; }
.view-switch { flex-wrap: nowrap; gap: .3rem; padding: 0; }
.view-switch .chip { padding: 0 .8rem; }
.view-switch .chip .icon { width: 1.15em; height: 1.15em; }
.view-switch .chip .sprout { width: 1.05rem; height: 1.3rem; margin-top: -.25rem; color: inherit; }
.view-switch .chip .sprout .soil { stroke: currentColor; opacity: .5; }
.view-switch .chip .sprout .grow { animation: none; }

.words-garden { padding: .9rem .8rem .55rem; }
.words-garden .garden { margin: 0 0 .25rem; }
.words-garden .garden-line { margin: .55rem .3rem .3rem; }

/* However many words there are, the last plant is up within a second. */
.words-garden .sprout .grow { animation-delay: calc(min(var(--i, 0), 14) * 45ms); }

/* Back from a word, the garden is as it was left: grown. A plant still sways when pointed at. */
.words-garden:where(.settled) .sprout .grow { animation: none; }

/* ---- 11. Progress shows growth ----
   The garden is the picture of it. Around it, numbers count up once, a line writes itself, columns
   grow from the baseline and the ring fills. Every one of these ends exactly on the picture that
   was there before any of them moved, and with "reduce motion" on they are simply there. */

/* A number that is the point of a screen counts up once to where it stands. The real number is
   always in the page. While it counts, a counter is shown in its place and the number waits. */
@keyframes count-wait { from { visibility: hidden; } }
@keyframes count-show { from { visibility: visible; } }

.counts-up { position: relative; display: inline-block; --count: var(--to, 0); counter-reset: count var(--count); animation: count-up .9s var(--ease-out) both, count-wait .9s step-end both; }
.counts-up::after { content: counter(count); position: absolute; top: 0; right: 0; visibility: hidden; animation: count-show .9s step-end both; }

/* The garden card: four numbers, one a stage, then every word as a plant. */
.garden-card { margin-top: .8rem; }
.garden-card .card-head .sub { flex: 0 0 auto; }
.garden-counts { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .3rem; margin: 0 0 .7rem; padding-bottom: .75rem; border-bottom: 1px solid var(--line); }
.garden-count { display: grid; grid-template-columns: auto auto; justify-content: center; align-items: end; column-gap: .3rem; text-align: center; }
.garden-count .sprout { width: 1.6rem; height: 2rem; }
.garden-count .n { font-family: var(--display); font-size: 1.45rem; font-weight: 800; line-height: 1.1; font-variant-numeric: tabular-nums; }
.garden-count .l { grid-column: 1 / -1; margin-top: .15rem; font-size: .82rem; line-height: 1.25; color: var(--ink-2); text-wrap: balance; }
.garden-card .garden { margin-bottom: .2rem; }
.garden-card .garden-line { margin: .5rem 0 0; }

/* However many words there are, the last plant is up within a second. */
.garden-card .garden .sprout .grow { animation-delay: calc(min(var(--i, 0), 24) * 30ms); }

/* On a phone the plants stand close together without their words. A tap on one still opens its word. */
@media (max-width: 599.98px) {
    .garden-card .garden.with-words { display: grid; grid-template-columns: repeat(auto-fill, minmax(2.75rem, 1fr)); gap: .1rem; margin-left: 0; margin-right: 0; }
    .garden-card .plant-word { display: none; }
}

@media (min-width: 600px) {
    .garden-counts { gap: .8rem; margin-bottom: .9rem; padding-bottom: .95rem; }
    .garden-count { column-gap: .55rem; }
    .garden-count .sprout { width: 2.2rem; height: 2.75rem; }
    .garden-count .n { font-size: 1.85rem; }
    .garden-count .l { font-size: .9rem; }
}

/* The headline numbers arrive one after another. */
.progress .stats > .stat { animation: rise var(--t) var(--ease-out) both; }
.progress .stats > .stat:nth-child(2) { animation-delay: 50ms; }
.progress .stats > .stat:nth-child(3) { animation-delay: 100ms; }
.progress .stats > .stat:nth-child(4) { animation-delay: 150ms; }
.progress .stats > .stat:nth-child(5) { animation-delay: 200ms; }
.progress .stats > .stat:nth-child(n+6) { animation-delay: 250ms; }

/* A line chart writes itself from left to right. Each point lands as the line reaches it, and the
   last value is written when the line gets there. The clip ends wider than the chart, so the
   finished line is not trimmed anywhere. */
@keyframes line-in { from { clip-path: inset(-1rem 100% -1rem -1rem); } to { clip-path: inset(-1rem); } }
.draws-in { --line-t: .9s; }
.draws-in .chart-svg { animation: line-in var(--line-t) linear both; }
.draws-in .chart-dot { animation: pop var(--t) var(--ease-spring) both; animation-delay: calc(var(--at, 0) * var(--line-t)); }
.draws-in .chart-label.end { animation: rise var(--t) var(--ease-out) both; animation-delay: var(--line-t); }

/* Columns grow from the baseline one after another, each carrying its number up with it. Only the
   start is written here, so a column always ends at its own height. */
@keyframes col-up { from { height: 0; } }
.grows-in .chart-bar { animation: col-up var(--t-slow) var(--ease-out) both; animation-delay: calc(var(--i, 0) * 45ms); }

/* The week's ring fills with one short sweep, from empty to where it stands. */
.ring-fill.sweeps { animation: ring-sweep .7s var(--ease-out) .1s both; }

/* ---- 12. The welcome: the first minute with the name ----
   Each step's picture plays once when the step arrives, and its words arrive from the right.
   --d is when a line of a picture starts, so a plant, its line and its words keep time. */

.scene { display: contents; }
.welcome-words { display: grid; gap: .7rem; justify-items: inherit; width: 100%; min-width: 0; animation: from-right var(--t) var(--ease-out) both; }
.welcome-wait { color: var(--ink-2); }
.lang { transition: background var(--t-fast) ease, transform var(--t-fast) var(--ease-out); }
.lang:active { transform: scale(.96); }

/* Step one. The name is the picture: large, in the middle, its mouth writing itself. Under it the
   three beats of the name: the red pen strikes the wrong spelling, the right one is written, and
   its straight line and its tick are drawn. */
.welcome-art.scene-0 .wordmark { position: static; font-size: clamp(3rem, 15vw, 4.4rem); }
.welcome-art.scene-0 .wm-mouth { animation: squiggle-in .5s var(--ease-out) .15s both; }
.scene-0 .scene-words { gap: .55rem; }
.scene-0 .scene-word { font-size: 1.3rem; text-decoration: none; }
.scene-0 .scene-word .struck { animation-delay: .6s; }
.scene-0 .scene-arrow { opacity: 1; color: color-mix(in srgb, currentColor 60%, transparent); animation: fade var(--t) ease 1.15s both; }
.scene-took { display: inline-flex; align-items: center; gap: .3rem; white-space: nowrap; }
.scene-0 .scene-word.right { position: relative; animation: rise var(--t) var(--ease-out) 1.2s both; }
.scene-0 .scene-word.right::after { content: ""; position: absolute; left: 0; right: 0; bottom: -.32em; height: .12em; border-radius: 2px; background: var(--green); transform-origin: 0 50%; animation: strike var(--t) var(--ease-out) 1.75s both; }
.scene-tick { width: 1.7rem; height: 1.7rem; flex: 0 0 auto; fill: none; stroke: var(--green); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
.scene-tick.draws path { animation-delay: 2s; }

/* The name's own story beside it: three words, a plant each, and what each means to a learner.
   Each line arrives on its beat of the picture. */
.name-story { list-style: none; display: grid; gap: .1rem; margin: .1rem 0; padding: 0; text-align: left; }
.name-story li { --d: .6s; display: grid; grid-template-columns: 1.9rem minmax(5.1rem, auto) minmax(0, 1fr); align-items: end; column-gap: .65rem; min-height: 2.4rem; animation: rise var(--t) var(--ease-out) var(--d) both; }
.name-story li:nth-child(2) { --d: 1.2s; }
.name-story li:nth-child(3) { --d: 1.8s; }
.name-story .sprout { width: 1.9rem; height: 2.4rem; }
.name-story .sprout .grow { animation-delay: var(--d); }
.name-story b { font-family: var(--display); font-size: 1.2rem; font-weight: 800; line-height: 1.5; }
.name-story span { color: var(--ink-2); line-height: 1.8; }

/* Step two. The four plants grow one after another, each with its line writing itself beside it. */
.scene-lines > div { --d: .1s; animation: rise var(--t) var(--ease-out) var(--d) both; }
.scene-lines > div:nth-child(2) { --d: .5s; }
.scene-lines > div:nth-child(3) { --d: .9s; }
.scene-lines > div:nth-child(4) { --d: 1.3s; }
.scene-lines .sprout .grow { animation-delay: var(--d); }
.scene-lines .stage-line { animation: squiggle-in .45s var(--ease-out) both; animation-delay: calc(var(--d) + .2s); }

/* Step three. Hear, type, say: the three round pictures pop one after another. */
.scene-row .scene-big { animation: pop var(--t) var(--ease-spring) .1s both; }
.scene-row .scene-big:nth-child(2) { animation-delay: .32s; }
.scene-row .scene-big:nth-child(3) { animation-delay: .54s; }
.scene-dots span { animation: pop var(--t) var(--ease-spring) .1s both; }
.scene-dots span:nth-child(2) { animation-delay: .25s; }
.scene-dots span:nth-child(3) { animation-delay: .4s; }

/* In one column the name sits in the corner of the picture, so the first line of four needs room
   under it. Every picture is as tall as that tallest one, so nothing under it moves between steps. */
@media (max-width: 839.98px) {
    .first-run .welcome-art { min-height: 16.9rem; }
    .welcome-art.scene-1 { padding-top: 3.5rem; }
    .name-story { justify-self: center; }
}

/* On a phone the buttons keep to the bottom of the screen, under the thumb, so Next is in the
   same place on every step however many words the step has. */
@media (max-width: 599.98px) {
    .first-run .welcome { min-height: calc(100dvh - var(--tabbar) - env(safe-area-inset-bottom, 0px) - 3.9rem); grid-template-rows: auto 1fr; }
    .first-run .welcome-say { grid-template-rows: auto 1fr; }
    .first-run .welcome-words { align-self: start; }
}

/* Where the buttons follow the words, the three pictures keep the room the first one's words need,
   so Next stays where it is from one picture to the next. */
@media (min-width: 600px) {
    .welcome-words.intro { min-height: 10.6rem; align-content: start; }
}

@media (min-width: 840px) {
    .welcome-words.intro { min-height: 14.2rem; }
    .welcome-art.scene-0 .wordmark { font-size: 4.6rem; }
    .scene-0 .scene-words { gap: .7rem; }
    .scene-0 .scene-word { font-size: 1.7rem; }
    .scene-tick { width: 2.1rem; height: 2.1rem; }
    .name-story b { font-size: 1.3rem; }
    .name-story span { font-size: 1.05rem; }
}

/* ---- 13. Doors, tiles and settings: calm arrivals, and things that answer the finger ----
   Tiles arrive one after another and lift a little when pointed at. Their arrival lets go of them
   when it ends (it fills backwards only), or it would hold them down against the lift. */

.tiles > .tile-big, .doors > .feature { animation: rise var(--t) var(--ease-out) backwards; animation-delay: calc(min(var(--i, 0), 12) * 40ms); }
.tile-big, .doors > .feature { transition: border-color var(--t-fast) ease, transform var(--t) var(--ease-out), box-shadow var(--t) ease; }
.tile-big .pic, .doors > .feature .pic { transition: transform var(--t) var(--ease-spring); }
.tile-big:active, .doors > .feature:active { transform: scale(.98); }

@media (hover: hover) {
    .tile-big:hover, .doors > .feature:hover { transform: translateY(-2px); box-shadow: var(--shadow); }
    .tile-big:hover .pic, .doors > .feature:hover .pic { transform: scale(1.08) rotate(-4deg); }
    .tile-big:active, .doors > .feature:active { transform: scale(.98); box-shadow: none; }
}

/* On a laptop every kind of practice is laid out under its own name: the kinds arrive one after
   another, and the tiles of a kind follow their heading. */
.more-group { animation: rise var(--t) var(--ease-out) both; animation-delay: calc(var(--g, 0) * 70ms); }
.more-group .doors > .feature { animation-delay: calc(var(--g, 0) * 70ms + min(var(--i, 0), 12) * 30ms); }

/* Settings. On a phone the headings arrive one after another. Where one is chosen from the list,
   the chosen one arrives beside the list. */
.settings .set-group { animation: rise var(--t) var(--ease-out) both; }
.settings .set-group:nth-child(2) { animation-delay: 50ms; }
.settings .set-group:nth-child(3) { animation-delay: 100ms; }
.settings .set-group:nth-child(4) { animation-delay: 150ms; }
.settings .set-group:nth-child(n+5) { animation-delay: 200ms; }

@media (min-width: 840px) {
    .settings .set-group.on { animation: from-right var(--t) var(--ease-out) both; }
    .set-nav .row .pic { transition: transform var(--t) var(--ease-spring); }
    .set-nav .row.on .pic { transform: scale(1.08); }
}

/* Switches and choices answer the finger. */
.settings label.check input, .gate label.check input { transition: transform var(--t-fast) var(--ease-out); }
.settings label.check:active input, .gate label.check:active input { transform: scale(.86); }
.size-btn { transition: background var(--t-fast) ease, border-color var(--t-fast) ease, color var(--t-fast) ease, transform var(--t-fast) var(--ease-out); }
.size-btn:active { transform: scale(.95); }
.settings select.input { transition: border-color var(--t-fast) ease, box-shadow var(--t-fast) ease; }
.set-state i { animation: pop var(--t) var(--ease-spring) both; }

/* On a phone the frame has no room for the name, so the name signs the bottom of Settings. */
.set-name { display: grid; justify-items: center; gap: .25rem; max-width: none; margin: 1.8rem 0 .3rem; }
.set-name .wordmark { font-size: 1.6rem; }
.set-line { font-family: var(--display); font-size: .95rem; font-weight: 700; color: var(--ink-3); }
@media (min-width: 600px) { .set-name { display: none; } }

/* The access code: the face shakes its head once at a wrong code. */
.gate-face { display: grid; justify-items: center; }
.gate-go .spinner { margin-right: .1rem; }
