/* Washi and seal — see the Foundations artboard. */
:root{
  --washi:#F3F0E7;--panel:#FBF9F3;--panel-soft:rgba(251,249,243,.7);
  --sumi:#1C1A17;--ink-muted:#6B645B;--ink-soft:#55504A;
  --hairline:#D9D2C1;--rule:#E2DCCE;--quiet-edge:#9A9287;
  --seal:#B8342A;--seal-deep:#8F2820;--seal-tint:#FAEDE9;--seal-edge:#C9705F;--seal-on:#FCF7EE;
  --indigo:#2E4A6B;
  --disabled-bg:#DFD9CB;--disabled-fg:#9A9287;--field-off:#EEEAE0;
  --chip-new-bd:#1C1A17;--chip-new-fg:#1C1A17;
  --chip-learn-bd:#9BA8B8;--chip-learn-bg:#ECEFF4;--chip-learn-fg:#2E4A6B;
  --chip-rev-bd:#C8C0AE;--chip-rev-bg:#F1EDE2;--chip-rev-fg:#55504A;
  --diff-wave:#B8342A;--diff-target-bg:#FAEDE9;
  --texture:rgba(28,26,23,.022);--texture-soft:rgba(28,26,23,.014);
  /* Theme-dependent values that are not plain colours. As tokens they follow
     the palette; as their own [data-theme="dark"] rules they missed the
     default theme, "system", which flips the palette but keeps that name. */
  --nav-bg:rgba(237,233,221,.6);--primary-weight:500;--quiet-title:#8C867C;
  --chevron:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='7' viewBox='0 0 10 7'><path d='M1 1l4 4 4-4' stroke='%2355504A' stroke-width='1.4' fill='none' stroke-linecap='round'/></svg>");
  --display:'Shippori Mincho','Hiragino Mincho ProN','Yu Mincho',Georgia,serif;
  --ui:'Zen Kaku Gothic New','Hiragino Sans','Yu Gothic',system-ui,sans-serif;
  color-scheme:light;
}
[data-theme="dark"]{
  --washi:#191712;--panel:#221F19;--panel-soft:rgba(34,31,25,.7);
  --sumi:#F2EEE3;--ink-muted:#A49B8C;--ink-soft:#C4BCAC;
  --hairline:#363028;--rule:#2C2820;--quiet-edge:#7D7568;
  --seal:#E0614B;--seal-deep:#EE8672;--seal-tint:#2A1E1A;--seal-edge:#7A3A30;--seal-on:#1A1611;
  --disabled-bg:#3D362D;--disabled-fg:#7D7568;--field-off:#1F1C16;
  --chip-new-bd:#F2EEE3;--chip-new-fg:#F2EEE3;
  --chip-learn-bd:#4C6182;--chip-learn-bg:#1E242E;--chip-learn-fg:#9DB4D4;
  --chip-rev-bd:#4A443A;--chip-rev-bg:#221F19;--chip-rev-fg:#C4BCAC;
  --diff-wave:#F5A691;--diff-target-bg:#3A241F;
  --texture:rgba(242,238,227,.022);--texture-soft:rgba(242,238,227,.014);
  --nav-bg:rgba(28,25,20,.6);--primary-weight:700;--quiet-title:#A49B8C;
  --chevron:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='7' viewBox='0 0 10 7'><path d='M1 1l4 4 4-4' stroke='%23C4BCAC' stroke-width='1.4' fill='none' stroke-linecap='round'/></svg>");
  color-scheme:dark;
}
@media(prefers-color-scheme:dark){
  [data-theme="system"]{
    --washi:#191712;--panel:#221F19;--panel-soft:rgba(34,31,25,.7);
    --sumi:#F2EEE3;--ink-muted:#A49B8C;--ink-soft:#C4BCAC;
    --hairline:#363028;--rule:#2C2820;--quiet-edge:#7D7568;
    --seal:#E0614B;--seal-deep:#EE8672;--seal-tint:#2A1E1A;--seal-edge:#7A3A30;--seal-on:#1A1611;
    --disabled-bg:#3D362D;--disabled-fg:#7D7568;--field-off:#1F1C16;
    --chip-new-bd:#F2EEE3;--chip-new-fg:#F2EEE3;
    --chip-learn-bd:#4C6182;--chip-learn-bg:#1E242E;--chip-learn-fg:#9DB4D4;
    --chip-rev-bd:#4A443A;--chip-rev-bg:#221F19;--chip-rev-fg:#C4BCAC;
    --diff-wave:#F5A691;--diff-target-bg:#3A241F;
    --texture:rgba(242,238,227,.022);--texture-soft:rgba(242,238,227,.014);
  --nav-bg:rgba(28,25,20,.6);--primary-weight:700;--quiet-title:#A49B8C;
  --chevron:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='7' viewBox='0 0 10 7'><path d='M1 1l4 4 4-4' stroke='%23C4BCAC' stroke-width='1.4' fill='none' stroke-linecap='round'/></svg>");
    color-scheme:dark;
  }
}

*{box-sizing:border-box}
html{background:var(--washi)}
body{margin:0;min-height:100dvh;font-family:var(--ui);font-size:15px;color:var(--sumi);background-color:var(--washi);background-image:repeating-linear-gradient(90deg,var(--texture) 0 1px,transparent 1px 3px),repeating-linear-gradient(0deg,var(--texture-soft) 0 1px,transparent 1px 4px);-webkit-font-smoothing:antialiased}
[hidden]{display:none!important}
button,input,textarea,select{font:inherit;color:inherit}
a{color:var(--seal)}
a:hover{color:var(--seal-deep)}
::placeholder{color:var(--disabled-fg);opacity:1}
:focus-visible{outline:2px solid var(--seal);outline-offset:3px}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}
.skip-link{position:absolute;left:-9999px;top:0;z-index:20;padding:.75rem 1rem;background:var(--panel);border:1px solid var(--sumi);border-radius:4px}
.skip-link:focus{left:8px;top:8px}

/* Header */
header{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:calc(24px + env(safe-area-inset-top)) 18px 14px;border-bottom:1px solid var(--hairline);position:sticky;top:0;z-index:10;background:var(--washi)}
.brand{display:flex;align-items:center;gap:9px}
.seal{width:26px;height:26px;flex-shrink:0;display:flex;align-items:center;justify-content:center;border-radius:3px;background:var(--seal);color:var(--seal-on);font-family:var(--display);font-size:15px;line-height:1}
h1{margin:0;font-family:var(--display);font-weight:400;font-size:19px;letter-spacing:.08em}
h2{margin:0;font-family:var(--display);font-weight:600;font-size:23px;letter-spacing:.04em}
.icon-button{width:44px;height:44px;flex-shrink:0;display:flex;align-items:center;justify-content:center;padding:0;background:var(--panel);border:1px solid var(--hairline);border-radius:4px;color:var(--sumi);cursor:pointer}
.icon-button svg{display:block}

main{padding:0 22px calc(94px + env(safe-area-inset-bottom));overflow-x:clip}
#main-view{padding-bottom:calc(12rem + env(safe-area-inset-bottom))}
body[data-view="session"] main{padding-bottom:calc(7rem + env(safe-area-inset-bottom))}
.section-title{display:flex;align-items:center;gap:12px;padding:18px 0 0}

/* Buttons */
button{min-height:44px;touch-action:manipulation;cursor:pointer;font-family:inherit}
button,.button{display:inline-flex;align-items:center;justify-content:center;gap:10px;padding:0 20px;background:var(--panel);color:var(--sumi);border:1px solid var(--sumi);border-radius:4px;font-size:15px;letter-spacing:.06em;text-decoration:none}
.primary{background:var(--seal);color:var(--seal-on);border-color:var(--seal);font-weight:var(--primary-weight)}
.quiet{border-color:var(--quiet-edge);color:var(--ink-soft)}
.plain{background:transparent;border-color:transparent;color:var(--ink-muted);letter-spacing:.04em}
button:disabled{background:var(--disabled-bg);color:var(--disabled-fg);border-color:transparent;cursor:default}
.controls{display:grid;gap:10px}
.controls button{min-height:56px;font-size:16px}

/* Fields */
label{display:grid;gap:7px}
.field-label,label>span:first-child{font-size:13px;color:var(--ink-soft)}
.overline{font-size:11px;text-transform:uppercase;letter-spacing:.16em;color:var(--ink-muted)}
input,textarea,select{width:100%;min-height:48px;padding:0 13px;background:var(--panel);color:var(--sumi);border:1px solid var(--hairline);border-radius:4px;outline:none}
textarea{padding:13px 14px;line-height:1.5;resize:none}
input[type=checkbox]{width:22px;height:22px;min-height:0;padding:0;accent-color:var(--seal)}
input[type=range]{min-height:0;padding:0;border:0;background:transparent;accent-color:var(--seal)}
input:disabled,textarea:disabled{background:var(--field-off);color:var(--disabled-fg);border-color:var(--disabled-bg)}
select{appearance:none;-webkit-appearance:none;padding-right:34px;background-image:var(--chevron);background-repeat:no-repeat;background-position:right 13px center}

/* Chips */
.toggles{display:flex;flex-wrap:wrap;gap:8px}
.toggles label{display:inline-flex;align-items:center;gap:7px;padding:9px 12px;background:var(--panel);border:1px solid var(--hairline);border-radius:3px;color:var(--ink-soft);font-size:13px;letter-spacing:.02em;cursor:pointer}
.toggles label:has(:checked){background:var(--seal-tint);border-color:var(--seal-edge);color:var(--seal-deep)}
.toggles input{width:14px;height:14px;margin:0}
.status-chip{display:inline-flex;align-self:flex-start;padding:3px 8px;border:1px solid var(--chip-rev-bd);border-radius:2px;background:var(--chip-rev-bg);color:var(--chip-rev-fg);font-size:10px;text-transform:uppercase;letter-spacing:.12em}
.status-chip.due{border-color:var(--seal-edge);background:var(--seal-tint);color:var(--seal-deep)}
.status-chip.new{border-color:var(--chip-new-bd);background:transparent;color:var(--chip-new-fg)}
.status-chip.learning{border-color:var(--chip-learn-bd);background:var(--chip-learn-bg);color:var(--chip-learn-fg)}

/* Japanese type */
[lang=ja]{font-family:var(--display)}
rt{font-size:.38em;font-weight:400;color:var(--ink-muted);letter-spacing:.04em}
.hide-furigana rt{visibility:hidden}
#japanese,#review-japanese{font-family:var(--display);font-weight:500;font-size:clamp(25px,7.4vw,29px);line-height:2.05;letter-spacing:.01em;overflow-wrap:anywhere}
#english-display{margin:12px 0 0;padding-left:13px;border-left:2px solid var(--hairline);font-size:14px;line-height:1.6;color:var(--ink-soft);overflow-wrap:anywhere}

/* Practice */
#practice{display:flex;flex-direction:column;padding-top:16px}
#japanese{margin:24px 0 0}
.counter{display:flex;align-items:baseline;justify-content:center;gap:10px;margin-top:2px}
.counter strong{font-family:var(--display);font-weight:600;font-size:34px;line-height:1}
.counter span{font-size:11px;text-transform:uppercase;letter-spacing:.2em;color:var(--ink-muted)}
.arcs{display:flex;justify-content:center;margin-top:26px;color:var(--seal)}
/* The Practice artboard sets the loop button 18px below the state line. .controls
   carries no margin of its own, so the button sat flush against "READY". */
#practice .controls{margin-top:18px}
/* The arcs share the ripple's clock: 2.4s, with the ripple's rings staggered
   every 0.6s inside it, so the two motions land on one grid instead of drifting
   against each other. The swing is narrowed too — the ripple peaks at .144
   once its .16 container is applied, so the board's .25-.8 arcs read about five
   times heavier and made the pair look like two different languages. */
#loop-state,#review-loop-state{display:flex;align-items:center;justify-content:center;gap:8px;margin:16px 0 0;font-size:12px;text-transform:uppercase;letter-spacing:.18em;color:var(--ink-soft)}
#loop-state::before,#review-loop-state::before{content:"";width:7px;height:7px;border-radius:50%;background:var(--hairline)}
.playing #loop-state::before,.playing #review-loop-state::before{background:var(--seal)}
.ripple{position:absolute;inset:auto;pointer-events:none;color:var(--seal)}
#welcome{padding-inline:4px}
.welcome{display:flex;flex-direction:column;justify-content:center;min-height:52dvh;position:relative}
.welcome strong{font-family:var(--display);font-weight:600;font-size:44px;line-height:1.18;letter-spacing:-.012em}
.welcome strong em{font-style:normal;color:var(--seal)}
.welcome .lede{margin:0;max-width:268px;font-size:15px;line-height:1.75;color:var(--ink-soft);text-wrap:pretty}
.welcome .stroke{width:52px;height:2px;background:var(--seal);margin:24px 0 16px}

/* Composer */
.composer{display:flex;flex-direction:column;gap:10px;padding:18px max(22px,env(safe-area-inset-right)) calc(20px + env(safe-area-inset-bottom)) max(22px,env(safe-area-inset-left));border-top:1px solid var(--hairline);background:var(--panel-soft);backdrop-filter:blur(12px)}
.input-row{display:flex;gap:10px;align-items:stretch}
.input-row textarea{flex-grow:1;min-width:0;height:54px}
.mic{width:54px;height:54px;flex-shrink:0;padding:0;background:var(--panel);border:1px solid var(--sumi);border-radius:4px}
.mic.is-listening{background:var(--seal);border-color:var(--seal);border-radius:50%;color:var(--seal-on)}
.input-row .primary{height:54px;flex-shrink:0;padding:0 16px}
/* On a phone the word costs the field most of a sentence: "Enter an English
   sentence" wrapped mid-placeholder. The arrow carries it instead — the same
   icon-only button the canvas already draws for the no-key composer — and the
   button keeps its aria-label, so the word is still there for a screen reader. */
@media(max-width:599px){#translate{width:54px;padding:0}#translate .label{display:none}
/* Two composers, as the canvas draws them. On the welcome screen the field gets
   its own row and two lines to sit in (Main); once a sentence is loaded it
   shrinks back to a single row beside the buttons (Practice). Held together in
   one row on a phone, the placeholder wrapped and was clipped mid-word. */
body:not(.has-sentence) .input-row{flex-wrap:wrap;justify-content:flex-end}
body:not(.has-sentence) .input-row textarea{flex-basis:100%;height:76px}}
.hint,#status{margin:0;font-size:12px;line-height:1.6;color:var(--ink-muted);text-wrap:pretty}
.hint:empty,#status:empty{display:none}
.error{color:var(--seal-deep)!important}

/* Lists */
ul{list-style:none;margin:0;padding:0}
.list-head{display:flex;align-items:baseline;justify-content:space-between;margin-top:18px;padding-bottom:9px;border-bottom:1px solid var(--sumi)}
.list-head span:first-child{font-family:var(--display);font-size:18px}
.list-head span:last-child{font-size:11px;text-transform:uppercase;letter-spacing:.16em;color:var(--ink-muted)}
#history-list li{display:flex;align-items:center;gap:10px;border-bottom:1px solid var(--rule)}
.history-open{display:flex;align-items:flex-start;gap:14px;flex-grow:1;min-width:0;min-height:0;padding:16px 0;background:transparent;border:0;border-radius:0;text-align:left;letter-spacing:normal}
.history-open .lines{flex-grow:1;min-width:0;display:flex;flex-direction:column;gap:5px}
.history-open [lang=ja]{font-size:18px;line-height:1.5;overflow-wrap:anywhere}
.history-open .en{font-size:13px;line-height:1.45;color:var(--ink-muted);overflow-wrap:anywhere}
.history-open .tally{flex-shrink:0;display:flex;flex-direction:column;align-items:flex-end;gap:2px;padding-top:2px}
.history-open .tally strong{font-family:var(--display);font-weight:600;font-size:19px;line-height:1}
.history-open .tally span{font-size:9px;text-transform:uppercase;letter-spacing:.14em;color:var(--ink-muted)}
.delete{width:44px;min-height:44px;padding:0;align-self:center;background:transparent;border:0;color:var(--seal-deep)}

/* Library tools */
.history-tools{display:flex;flex-direction:column;gap:10px;margin-top:18px;padding:13px;background:var(--panel);border:1px solid var(--hairline);border-radius:4px}
.search-control{display:flex;align-items:center;gap:10px;height:44px;padding:0 12px;background:var(--washi);border:1px solid var(--rule);border-radius:3px}
.search-control input{min-height:0;height:100%;padding:0;background:transparent;border:0;border-radius:0}
.search-icon{flex-shrink:0;display:flex;color:var(--ink-muted)}
.search-control button{width:34px;min-height:34px;flex-shrink:0;padding:0;background:transparent;border:0;color:var(--ink-muted)}
.history-filter-row{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:7px}
.history-filter-row label{gap:5px}
.history-filter-row span{font-size:10px;text-transform:uppercase;letter-spacing:.14em;color:var(--ink-muted)}
.history-filter-row select{min-height:38px;height:38px;padding:0 24px 0 9px;background-color:var(--washi);border-color:var(--rule);border-radius:3px;font-size:13px;background-position:right 9px center}
#empty-history,#empty-results{margin:40px 0;text-align:center;font-family:var(--display);font-size:18px;color:var(--ink-soft)}

/* Review */
.review-card{display:grid;gap:22px;width:100%;min-height:42dvh;padding:26px 0;background:transparent;border:0;border-radius:0;text-align:left;place-content:center;letter-spacing:normal}
#review-english{font-size:18px;line-height:1.6;color:var(--ink-soft);padding-top:18px;border-top:1px solid var(--rule)}
#review-hint{font-size:12px;text-transform:uppercase;letter-spacing:.18em;color:var(--ink-muted)}
.review-loop-status{display:flex;flex-direction:column;align-items:center;gap:4px}
.review-loop-status .counter{margin:0}
#review-progress{margin-left:auto;font-family:var(--display);font-size:16px;letter-spacing:.06em;color:var(--ink-soft)}
.review-actions{position:fixed;z-index:4;left:50%;bottom:0;transform:translateX(-50%);width:min(760px,100%);display:grid;grid-template-columns:1fr 1fr;gap:12px;padding:16px max(22px,env(safe-area-inset-right)) calc(16px + env(safe-area-inset-bottom)) max(22px,env(safe-area-inset-left));border-top:1px solid var(--hairline);background:var(--panel-soft);backdrop-filter:blur(12px)}
.review-actions button{min-height:58px;font-size:16px;font-weight:500}
.review-actions .again{border-color:var(--quiet-edge);color:var(--ink-soft)}
#review-view{display:flex;flex-direction:column;min-height:calc(100dvh - 40px)}
#review-complete{align-items:center;text-align:center;min-height:56dvh}
#review-complete strong{font-family:var(--display);font-weight:600;font-size:32px;letter-spacing:.01em}
#review-complete .lede{max-width:280px;text-align:center}
#review-complete .controls{margin-top:24px;width:100%}
.stamp{width:78px;height:78px;display:flex;align-items:center;justify-content:center;border-radius:5px;background:var(--seal);color:var(--seal-on);font-family:var(--display);font-size:42px;line-height:1}

/* Notices */
.notice{display:flex;align-items:flex-start;gap:12px;padding:15px 16px;border:1px solid var(--chip-rev-bd);border-radius:4px;background:var(--chip-rev-bg)}
.notice.alert{border-color:var(--seal-edge);background:var(--seal-tint)}
.notice>svg{flex-shrink:0;margin-top:2px;color:var(--ink-soft)}
.notice.alert>svg{color:var(--seal-deep)}
.notice-body{flex-grow:1;min-width:0;display:flex;flex-direction:column;gap:6px}
.notice-title{font-size:14px;font-weight:500;color:var(--sumi)}
.notice.alert .notice-title{color:var(--seal-deep)}
.notice-copy{font-size:13px;line-height:1.55;color:var(--ink-soft);text-wrap:pretty}
.notice-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:2px}
.notice-actions button{min-height:36px;height:36px;padding:0 14px;border-radius:3px;font-size:13px;letter-spacing:normal}
.notice.alert .notice-actions button{border-color:var(--seal-deep);color:var(--seal-deep)}
.notice.alert .notice-actions button.outline{border-color:var(--seal-edge)}
/* The action that clears a blocked state has to be tappable, but the banner was
   drawn around 13px text. The box stays text-sized in flow and a transparent
   pseudo-element carries the touch target out to 44px, so nothing shifts. */
.notice-link{position:relative;align-self:flex-start;margin-top:2px;font-size:13px;font-weight:500;letter-spacing:.02em;background:none;border:0;padding:0;min-height:0;color:var(--seal);text-decoration:underline}
.notice-link::after{content:"";position:absolute;left:0;right:0;top:50%;height:44px;transform:translateY(-50%)}
.dock{position:fixed;z-index:3;left:50%;bottom:calc(72px + env(safe-area-inset-bottom));transform:translateX(-50%);width:min(760px,100%)}
#practice-notices:not(:empty){padding:0 22px 14px}
.empty-panel{display:flex;flex-direction:column;align-items:center;gap:10px;margin-top:24px;padding:20px 18px;border:1px solid var(--hairline);border-radius:4px;background:var(--panel);text-align:center}
.empty-panel strong{font-family:var(--display);font-weight:400;font-size:18px}
.empty-panel span{font-size:13px;color:var(--ink-soft)}
.empty-panel button{min-height:38px;height:38px;margin-top:4px;padding:0 16px;border-radius:3px;font-size:13px;letter-spacing:normal;background:transparent}

/* No translator connected */
body.no-key #welcome strong,body.no-key #welcome strong em{color:var(--quiet-title)}
body.no-key #translate{width:52px;padding:0}
body.no-key #translate .label{display:none}
body.no-key #welcome .stroke{background:var(--chip-rev-bd)}
body.no-key #welcome .lede{color:var(--ink-muted)}
body.no-key .ripple{stroke-opacity:.12}
body.no-key .composer label{color:var(--disabled-fg)}
body.no-key .mic{display:none}

/* First run */
#onboard-view,#setup-view{display:flex;flex-direction:column;min-height:calc(100dvh - 40px);padding-top:8px}
.onboard-stage{flex-grow:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:0;position:relative;text-align:center;padding:24px 12px}
.onboard-stage .ripple{top:-60px;left:50%;transform:translateX(-50%);stroke-opacity:.14}
.seal.big{position:relative;width:92px;height:92px;border-radius:6px;font-size:52px}
.onboard-title{position:relative;margin:32px 0 0;font-family:var(--display);font-weight:600;font-size:46px;letter-spacing:.04em}
.onboard-stage .lede{position:relative;margin:18px 0 0;max-width:280px;font-size:16px;line-height:1.75;color:var(--ink-soft);text-wrap:pretty}
.steps{position:relative;display:flex;flex-direction:column;gap:14px;margin:36px 0 0;padding:26px 0 0;list-style:none;border-top:1px solid var(--hairline)}
.steps li{display:flex;align-items:center;gap:12px;text-align:left;font-size:14px;color:var(--ink-soft)}
.step-mark{width:26px;height:26px;flex-shrink:0;display:flex;align-items:center;justify-content:center;border:1px solid var(--seal-edge);border-radius:3px;color:var(--seal-deep);font-family:var(--display);font-size:14px}
.plain-sheet{margin:0;border-top:0;background:transparent;padding-bottom:calc(30px + env(safe-area-inset-bottom))}
.plain-sheet .primary{min-height:58px;font-size:17px}
.setup-title{margin:16px 0 0;font-family:var(--display);font-weight:600;font-size:34px;line-height:1.3;letter-spacing:-.01em}
.setup-copy{margin:14px 0 0;font-size:15px;line-height:1.75;color:var(--ink-soft);text-wrap:pretty}
.setup-field{gap:8px;margin-top:18px}
.setup-field:first-of-type{margin-top:28px}
.setup-field select,.setup-field input{min-height:52px;height:52px;font-size:16px}
#setup-hint{margin-top:10px}
.note-box{display:flex;gap:11px;margin-top:26px;padding:15px 16px;border:1px solid var(--hairline);border-radius:4px;background:var(--panel)}
.note-box>svg{flex-shrink:0;margin-top:2px;color:var(--seal-deep)}
.note-box p{margin:0;font-size:13px;line-height:1.6;color:var(--ink-soft);text-wrap:pretty}

/* Sentence detail */
#sentence-view{display:flex;flex-direction:column;min-height:calc(100dvh - 40px)}
#sentence-view .session-bar{border-bottom:1px solid var(--hairline);margin-bottom:24px}
#sentence-added{flex-grow:1;letter-spacing:.18em}
#sentence-japanese{margin:0;font-family:var(--display);font-weight:500;font-size:30px;line-height:2;letter-spacing:.01em;overflow-wrap:anywhere}
#sentence-english{margin:14px 0 0;padding-left:13px;border-left:2px solid var(--hairline);font-size:15px;line-height:1.6;color:var(--ink-soft);overflow-wrap:anywhere}
.sentence-controls{display:flex;gap:10px;margin-top:22px}
.sentence-controls .primary{flex-grow:1;min-height:52px}
#sentence-view .stats strong{position:relative}
.icon-button.square{width:52px;height:52px;border-color:var(--sumi)}
#sentence-editor{display:flex;flex-direction:column;gap:10px;margin-top:22px}
#sentence-editor .answer-box{border-color:var(--hairline)}
#sentence-editor textarea{font-size:20px;line-height:1.9}
.editor-actions{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:4px}
.editor-actions button{min-height:52px;font-size:16px}
.stats{display:flex;align-items:stretch;margin-top:24px;padding:16px 0;border-top:1px solid var(--hairline);border-bottom:1px solid var(--hairline)}
.stats>span{flex:1 1 0;display:flex;flex-direction:column;align-items:center;gap:4px}
.stats strong{font-family:var(--display);font-weight:600;font-size:24px}
/* the chip is shorter than the numbers beside it, so it sits in a band of the
   same height — otherwise all three labels land on different lines */
.stats .band{display:flex;align-items:center;justify-content:center;min-height:27px}
.stats .status-chip{align-self:center}
.stats>span>span:last-child{font-size:10px;text-transform:uppercase;letter-spacing:.14em;color:var(--ink-muted)}
.stats .divider{flex:0 0 1px;padding:0;background:var(--rule)}
.rule-heading{display:flex;align-items:center;gap:12px;margin:24px 0 0;font-size:11px;font-weight:500;text-transform:uppercase;letter-spacing:.2em;color:var(--seal-deep)}
.rule-heading::after{content:"";flex-grow:1;height:1px;background:var(--hairline)}
#sentence-history{margin-top:10px}
#sentence-history li{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:11px 0;border-bottom:1px solid var(--rule)}
#sentence-history .when{font-size:14px;color:var(--ink-soft)}
#sentence-history .detail{display:flex;align-items:center;gap:9px}
#sentence-history .echoes{font-size:12px;color:var(--ink-muted)}
.rating-chip{padding:3px 9px;border:1px solid var(--chip-rev-bd);border-radius:2px;color:var(--ink-soft);font-size:11px}
.rating-chip.again{border-color:var(--seal-edge);background:var(--seal-tint);color:var(--seal-deep)}
.rating-chip.first{border-color:var(--chip-new-bd);color:var(--chip-new-fg)}
#sentence-history-note{margin-top:14px}
.sentence-danger{margin-top:auto;padding:18px 0 30px;border-top:1px solid var(--hairline)}
.danger{width:100%;min-height:50px;background:transparent;border-color:var(--seal-edge);color:var(--seal-deep);letter-spacing:.04em}
.sheet-dialog{position:fixed;width:100%;max-width:none;margin:auto auto 0;padding:28px 22px calc(32px + env(safe-area-inset-bottom));border:0;border-top:2px solid var(--seal);border-radius:8px 8px 0 0;background:var(--panel);box-shadow:0 -14px 40px rgba(28,26,23,.18)}
.sheet-dialog h2{margin:0;font-size:26px;line-height:1.35}
.danger-mark{width:44px;height:44px;display:flex;align-items:center;justify-content:center;margin-bottom:14px;border:1px solid var(--seal-edge);border-radius:4px;background:var(--seal-tint);color:var(--seal-deep)}
#delete-quote{margin:14px 0 0;padding:12px 14px;border-left:2px solid var(--hairline);background:var(--washi);font-family:var(--display);font-size:18px;line-height:1.6;color:var(--ink-soft);overflow-wrap:anywhere}
#delete-copy{margin:14px 0 0;font-size:14px;line-height:1.65;color:var(--ink-soft);text-wrap:pretty}
.sheet-dialog .dialog-actions{margin-top:18px;padding:0;border-top:0;background:transparent}
.sheet-dialog .dialog-actions button{min-height:56px}

/* Settings */
dialog{width:min(94vw,520px);max-height:calc(100dvh - 2rem);margin:auto;padding:0;overflow:auto;background:var(--washi);color:var(--sumi);border:1px solid var(--hairline);border-radius:6px}
dialog::backdrop{background:rgba(28,26,23,.34)}
.dialog-title{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:20px 22px 14px;border-bottom:1px solid var(--hairline)}
.settings-section{display:flex;flex-direction:column;gap:12px;padding:0 22px;margin-top:26px}
/* A settings row is a hit target: the whole label toggles the switch. Rows
   whose description wraps are already taller, but a one-line row came out at
   39px on wide viewports, so the row carries the 44px floor itself. */
.switch{display:flex;align-items:center;min-height:44px;gap:14px;cursor:pointer}
.switch-copy{flex-grow:1;min-width:0;display:flex;flex-direction:column;gap:4px}
.switch-copy>span:first-child{font-size:14px;color:var(--sumi)}
.switch input{flex-shrink:0;width:22px}
.time-row{justify-content:space-between}
.time-row>span{font-size:13px;color:var(--ink-soft)}
.time-row select{width:160px;min-height:44px;height:44px}
#remind-reach:empty{display:none}
.settings-section h3{display:flex;align-items:center;gap:12px;margin:0;font-size:11px;font-weight:500;text-transform:uppercase;letter-spacing:.2em;color:var(--seal-deep)}
.settings-section h3::after{content:"";flex-grow:1;height:1px;background:var(--hairline)}
.rate-setting{display:grid;gap:9px}
.rate-row{display:flex;align-items:baseline;justify-content:space-between}
.rate-setting output{font-family:var(--display);font-size:16px;color:var(--seal)}
.provider-config{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
.provider-config label{grid-column:span 1}
.provider-config .hint,.provider-config label:only-child{grid-column:1/-1}
.asset-row{display:flex;align-items:center;gap:14px;padding:13px 0;border-bottom:1px solid var(--rule)}
.asset-row:last-of-type{border-bottom:0}
.asset-copy{flex-grow:1;min-width:0;display:flex;flex-direction:column;gap:4px}
.asset-copy strong{font-family:var(--display);font-weight:400;font-size:17px}
.asset-actions{flex-shrink:0;display:flex;gap:8px}
.asset-actions button{height:40px;min-height:40px;padding:0 16px;font-size:14px;letter-spacing:.04em}
.install-panel{display:flex;align-items:center;justify-content:space-between;gap:14px;margin:26px 22px 0;padding:16px 18px;background:var(--panel);border:1px solid var(--hairline);border-radius:4px}
.install-panel div{display:flex;flex-direction:column;gap:3px}
.install-panel strong{font-family:var(--display);font-weight:400;font-size:17px}
.install-panel button{height:44px;flex-shrink:0;padding:0 18px;background:transparent;font-size:14px;letter-spacing:.04em}
#install-status{margin:8px 22px 0}
.dialog-actions{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:26px;padding:18px 22px calc(22px + env(safe-area-inset-bottom));border-top:1px solid var(--hairline);background:var(--panel-soft)}
.dialog-actions button{min-height:54px;font-size:16px}

/* Tabs */
.tabs>.nav-brand,.tabs>.nav-settings{display:none}
.tabs{position:fixed;z-index:5;left:0;right:0;bottom:0;display:flex;border-top:1px solid var(--hairline);background:var(--panel);padding-bottom:env(safe-area-inset-bottom)}
.tab{flex:1 1 0;min-width:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:5px;height:72px;padding:0;background:transparent;border:0;border-top:2px solid transparent;margin-top:-1px;border-radius:0;color:var(--ink-soft);font-size:11px;letter-spacing:.08em}
.tab.current{color:var(--seal);border-top-color:var(--seal)}
.tab-icon{position:relative;display:flex}
.tab-badge{position:absolute;top:-6px;left:13px;min-width:17px;height:17px;padding:0 4px;display:flex;align-items:center;justify-content:center;border-radius:2px;background:var(--seal);color:var(--seal-on);font-size:10px;line-height:1}

/* Review home */
#review-home{display:flex;flex-direction:column;min-height:calc(100dvh - 160px)}
.ring-stage{flex-grow:1;display:flex;flex-direction:column;align-items:center;justify-content:center;position:relative;text-align:center;padding:24px 4px}
/* The rings are concentric with the count, not with the stage: the artboard
   puts the ripple's top exactly one count-height (112px) above it, which leaves
   the outermost ring tucked 22px clear of the breakdown bar. Anchored to the
   stage instead, the ripple drifted against the centred content as the viewport
   grew or shrank, and on a short screen its bottom swept down through the
   breakdown. */
.ring-core{position:relative;display:flex;flex-direction:column;align-items:center}
.ring-stage .ripple{top:-142px;left:50%;transform:translateX(-50%)}
.ring-stage.resting .ripple{color:var(--sumi);stroke-opacity:.08}
#review-due-block,#review-rest-block{position:relative;display:flex;flex-direction:column;align-items:center}
#due-count{font-family:var(--display);font-weight:600;font-size:112px;line-height:1;color:var(--seal)}
#review-due-block .overline{margin-top:10px;letter-spacing:.22em}
#review-estimate,#review-rest-copy{margin:20px 0 0;max-width:260px;font-size:15px;line-height:1.7;color:var(--ink-soft);text-wrap:pretty}
.glyph{width:62px;height:62px;display:flex;align-items:center;justify-content:center;border:1px solid var(--chip-rev-bd);border-radius:4px;color:var(--ink-soft);font-family:var(--display);font-size:30px;line-height:1}
.rest-title{margin-top:26px;font-family:var(--display);font-weight:600;font-size:30px}
.breakdown{position:relative;display:flex;gap:22px;margin-top:30px;padding-top:20px;border-top:1px solid var(--hairline)}
.breakdown>span{display:flex;flex-direction:column;align-items:center;gap:4px}
.breakdown strong{font-family:var(--display);font-weight:600;font-size:22px}
.breakdown>span>span{font-size:10px;text-transform:uppercase;letter-spacing:.14em;color:var(--ink-muted)}
.breakdown .divider{width:1px;padding:0;background:var(--hairline)}
#review-prompt-actions{margin-top:auto}
#review-prompt-actions .primary{min-height:60px}
#review-prompt-actions .plain{min-height:46px}
.sheet{display:flex;flex-direction:column;gap:10px;margin:0 -22px;padding:18px 22px 20px;border-top:1px solid var(--hairline);background:var(--panel-soft)}
.sheet>button{min-height:56px;font-size:16px}
.sheet .primary{min-height:58px;font-size:17px}
.sheet .hint{text-align:center}

/* Review prompt and answer */
#review-panel{display:flex;flex-direction:column;padding-top:24px}
#review-stage{align-self:flex-start}
#review-prompt{margin:22px 0 0;font-family:var(--display);font-weight:500;font-size:28px;line-height:1.5;letter-spacing:-.01em;text-wrap:pretty}
#review-capture>.overline{display:block;margin:26px 0 9px}
.answer-box{display:flex;flex-direction:column;gap:12px;padding:14px 14px 12px;border:1px solid var(--seal-edge);border-radius:5px;background:var(--panel)}
.answer-box textarea{min-height:0;padding:0;border:0;border-radius:0;background:transparent;font-family:var(--display);font-size:23px;line-height:1.7}
.answer-box:has(textarea:focus-visible){outline:2px solid var(--seal);outline-offset:3px}
.answer-box textarea:focus-visible{outline:none}
.answer-tools{display:flex;align-items:center;gap:12px;padding-top:10px;border-top:1px solid var(--rule)}
.mic-round{width:46px;height:46px;min-height:46px;flex-shrink:0;padding:0;background:var(--panel);border:1px solid var(--sumi);border-radius:50%}
.mic-round[aria-pressed="true"]{background:var(--seal);border-color:var(--seal);color:var(--seal-on)}
.answer-copy{flex-grow:1;min-width:0;display:flex;flex-direction:column;gap:3px}
#review-listen-state{font-size:13px;letter-spacing:.02em;color:var(--seal-deep)}
#review-listen-state:empty{display:none}
.answer-copy .hint{font-size:11px;line-height:1.5}
.arcs.small{flex-shrink:0;display:flex;opacity:0}
.is-listening .arcs.small{opacity:1}
#review-check svg{flex-shrink:0}

/* Review answer */
#review-result{display:flex;flex-direction:column;padding-top:22px}
#review-prompt-echo{margin:0;font-size:13px;line-height:1.6;color:var(--ink-muted)}
#review-result .overline{margin:18px 0 7px}
#review-result .overline.target{margin-top:20px;color:var(--seal-deep)}
#review-attempt{margin:0;font-family:var(--display);font-size:22px;line-height:1.7;color:var(--ink-soft);overflow-wrap:anywhere}
#review-attempt mark{background:transparent;color:var(--seal-deep);text-decoration:underline wavy var(--diff-wave);text-underline-offset:6px}
#review-japanese{margin:0;font-family:var(--display);font-weight:500;font-size:28px;line-height:1.95;letter-spacing:.01em;overflow-wrap:anywhere}
#review-japanese mark{background:var(--diff-target-bg);color:var(--seal-deep)}
#review-result .arcs{margin-top:20px}
#review-result .counter{margin-top:2px}
#review-result .controls{margin-top:16px}
#review-result .controls button{min-height:50px;font-size:15px;font-weight:500}
#review-empty-answer{margin:18px 0 0}

/* Review session */
.session-bar{display:flex;align-items:center;gap:12px;padding:calc(24px + env(safe-area-inset-top)) 0 14px}
.session-bar h2{flex-grow:1;font-size:20px}
.progress-track{height:3px;background:var(--rule)}
#review-progress-bar{height:3px;width:0;background:var(--seal);transition:width .28s ease-out}

/* Desktop side panel */
#side-panel{display:none}
.grow{flex-grow:1}
.side-cta{width:100%;height:64px;justify-content:space-between;padding:0 18px}
.side-cta strong{font-family:var(--display);font-weight:600;font-size:28px;line-height:1}
#due-list li,#queue-list li{border-bottom:1px solid var(--rule)}
#due-list button{display:flex;flex-direction:column;align-items:flex-start;gap:4px;width:100%;min-height:0;padding:14px 0;background:transparent;border:0;border-radius:0;text-align:left;letter-spacing:normal}
#due-list [lang=ja]{font-family:var(--display);font-size:16px;line-height:1.5;overflow-wrap:anywhere}
#due-list .en,#queue-list .en{font-size:12px;line-height:1.5;color:var(--ink-muted);overflow-wrap:anywhere}
#queue-list li{display:flex;align-items:center;gap:11px;padding:13px 0}
#queue-list .dot{width:7px;height:7px;flex-shrink:0;border-radius:50%;border:1px solid var(--chip-rev-bd)}
#queue-list li.now .dot{background:var(--seal);border-color:var(--seal)}
#queue-list li.now .en{color:var(--sumi)}
#queue-list li.done .dot{background:var(--chip-rev-bd)}
.keys{display:none;flex-direction:column;gap:9px;margin-top:auto;padding:16px;border:1px solid var(--hairline);border-radius:4px;background:var(--panel)}
.keys>span{display:flex;align-items:center;gap:9px;font-size:12px;color:var(--ink-soft)}
.keys .overline{letter-spacing:.18em}
kbd{padding:2px 7px;border:1px solid var(--chip-rev-bd);border-radius:3px;background:var(--panel);font-family:var(--display);font-size:12px;color:var(--ink-soft)}

/* Motion */

@media(min-width:700px){
  header{padding-inline:32px}
  main{max-width:760px;margin:auto;padding-inline:32px}
  .composer{padding-inline:32px}
  #practice-notices:not(:empty){padding-inline:32px}
}
@media(min-width:1024px){
  body{display:grid;grid-template-columns:264px minmax(0,1fr);grid-template-rows:auto 1fr;align-content:start;min-height:100dvh}
  header{display:none}
  main{grid-column:2;grid-row:1/3;max-width:880px;margin:0;padding:36px 56px calc(40px + env(safe-area-inset-bottom))}
  #main-view{padding-bottom:13rem}
  body[data-view="session"] main{padding-bottom:7rem}
  .tabs{grid-column:1;grid-row:1/3;position:sticky;top:0;left:auto;right:auto;bottom:auto;align-self:start;height:100dvh;flex-direction:column;justify-content:flex-start;gap:3px;padding:34px 24px;border-top:0;border-right:1px solid var(--hairline);background:var(--nav-bg)}
  .tabs>.nav-brand{display:flex;align-items:center;gap:11px;padding:0 0 28px;margin-bottom:22px;border-bottom:1px solid var(--hairline)}
  .nav-brand .seal{width:30px;height:30px;font-size:17px}
  .nav-wordmark{font-family:var(--display);font-size:21px;letter-spacing:.08em}
  .tab{flex:0 0 auto;height:46px;flex-direction:row;justify-content:flex-start;gap:12px;padding:0 13px;border-top:0;border-radius:4px;margin-top:0;font-size:15px;letter-spacing:normal}
  .tab.current{background:var(--panel);border:1px solid var(--hairline);color:var(--sumi)}
  .tab.current .tab-icon{color:var(--seal)}
  .tab-badge{position:static;margin-left:auto;min-width:24px;height:22px;font-size:12px}
  .tabs>.nav-settings{display:flex}
  .dock{left:264px;right:340px;bottom:0;transform:none;width:auto}
  #practice-notices:not(:empty){padding-inline:56px}
  .composer{padding-inline:56px}
  .review-actions{left:264px;right:300px;transform:none;width:auto;padding-inline:56px}
  .sheet{margin:0;border-radius:4px}
  #review-home{min-height:auto}
  .session-bar{padding-top:8px}
  body[data-view="session"] .keys{display:flex}

  /* Practice keeps a Due now rail; a session keeps the queue it is working through */
  body[data-view="practice"]{grid-template-columns:264px minmax(0,1fr) 340px}
  body[data-view="session"]{grid-template-columns:264px minmax(0,1fr) 300px}
  body[data-view="practice"] #side-panel,body[data-view="session"] #side-panel{display:flex}
  #side-panel{grid-column:3;grid-row:1/3;flex-direction:column;gap:14px;min-width:0;height:100dvh;position:sticky;top:0;padding:36px 26px;border-left:1px solid var(--hairline);background:var(--panel-soft);overflow-y:auto}
  #side-panel>div{display:flex;flex-direction:column;gap:14px;flex-grow:1;min-height:0}

  /* Library is a list beside the sentence it is showing */
  body[data-view="library"],body[data-view="sentence"]{grid-template-columns:236px 400px minmax(0,1fr)}
  body[data-view="library"] main,body[data-view="sentence"] main{display:contents}
  body[data-view="library"] #history-view,body[data-view="sentence"] #history-view{grid-column:2;grid-row:1/3;height:100dvh;overflow-y:auto;padding:26px 22px;border-right:1px solid var(--hairline)}
  body[data-view="sentence"] #sentence-view{grid-column:3;grid-row:1/3;min-height:auto;height:100dvh;overflow-y:auto;padding:36px 44px 30px}
  body[data-view="sentence"] .session-bar .icon-button{display:none}
  #history-list li.selected{margin-inline:-10px;padding-inline:7px 10px;border-left:3px solid var(--seal);background:var(--seal-tint)}
}

/* Echo — the echo animation. Copy this file verbatim into styles.css.
 *
 * This is the spec, not an illustration of it. Every number here was
 * measured on the canvas; do not re-derive them from prose.
 *
 * ── The whole idea ──────────────────────────────────────────────────
 * The resting state IS the drawn ripple: rings sitting at their final
 * radii, exactly as every artboard draws them. Playing does not add a
 * new graphic — it animates the one already there. So "not playing",
 * "paused" and "reduced motion" are all the same state, for free, and
 * there is no second thing to keep in sync.
 *
 * Movement means one thing: audio is playing right now. Nothing else
 * in the app moves.
 */

/* ── 1. The container ──────────────────────────────────────────────
 * One element wraps the rings. Its stroke-opacity is the ripple's
 * weight, and it is NOT the same still and moving: a ring is at full
 * strength for an instant and spends most of its cycle fading, so
 * .16 measures as an effective .144 in motion. Lift it while playing.
 * (Element opacity in the keyframes multiplies with this: .234 × .9
 * = .21 at the peak.)
 */
.echo {
  stroke-opacity: 0.16;
}
.echo.is-playing {
  stroke-opacity: 0.234;
}

/* ── 2. Resting: the drawn ripple ───────────────────────────────────
 * Four rings at .34 / .55 / .78 / 1 of the outer radius — the ratios
 * the artboards use. Author every ring at the OUTER radius in the
 * markup and scale it down here, so one animation can drive all four.
 *
 * transform-origin is the trap. SVG's default puts it at the corner of
 * the coordinate system, not the middle of the shape, and it is NOT
 * inherited — setting it on the parent <g> does nothing. Both the
 * design and the build shipped rings flying out of the top-left before
 * catching this. It must sit on the animated element itself.
 */
.echo-ring {
  transform-box: view-box;
  transform-origin: center;
}
.echo-ring:nth-of-type(1) { transform: scale(0.34); }
.echo-ring:nth-of-type(2) { transform: scale(0.55); }
.echo-ring:nth-of-type(3) { transform: scale(0.78); }
.echo-ring:nth-of-type(4) { transform: scale(1); }

/* ── 3. Playing: one ring leaves the centre per pass ────────────────
 * 2.4s ÷ 4 rings = 0.6s stagger, so the cadence is even. 0.8s across
 * four rings leaves a 0.8s hole in every cycle — that was the first
 * build's bug, and it is why the number is 0.6 and not 0.8.
 */
@keyframes echo-emanate {
  0%   { transform: scale(0.24); opacity: 0.9; }
  65%  {                         opacity: 0.3; }
  100% { transform: scale(1);    opacity: 0;   }
}

.echo.is-playing .echo-ring {
  animation: echo-emanate 2.4s ease-out infinite;
}
.echo.is-playing .echo-ring:nth-of-type(2) { animation-delay: 0.6s; }
.echo.is-playing .echo-ring:nth-of-type(3) { animation-delay: 1.2s; }
.echo.is-playing .echo-ring:nth-of-type(4) { animation-delay: 1.8s; }

/* ── 4. The arc pair — same motion, compact form ────────────────────
 * Used inline, beside the echo count. Three copies of ONE arc pair,
 * not three arcs at different radii: author all three at the outer
 * radius, rest them at .24 / .6 / 1, animate the same keyframes.
 * Stagger 0.8s (2.4 ÷ 3).
 *
 * The arcs must be arcs of circles centred on the middle of their
 * viewBox — then `transform-origin: center` is the right point and the
 * rule above serves them too.
 */
.echo-arc {
  transform-box: view-box;
  transform-origin: center;
}
.echo-arc:nth-of-type(1) { transform: scale(0.24); }
.echo-arc:nth-of-type(2) { transform: scale(0.6); }
.echo-arc:nth-of-type(3) { transform: scale(1); }

.echo.is-playing .echo-arc {
  animation: echo-emanate 2.4s ease-out infinite;
}
.echo.is-playing .echo-arc:nth-of-type(2) { animation-delay: 0.8s; }
.echo.is-playing .echo-arc:nth-of-type(3) { animation-delay: 1.6s; }

/* ── 5. Listening ──────────────────────────────────────────────────
 * The mic GLYPH fades; the button itself never moves or resizes.
 */
@keyframes echo-listening {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.4; }
}
.is-listening .mic-glyph {
  animation: echo-listening 1.4s ease-in-out infinite;
}

/* ── 6. The count going up ─────────────────────────────────────────
 * Add .just-ticked when the number changes, remove it on animationend.
 * Rises and fades in. No bounce, no colour flash, no scale.
 */
@keyframes echo-tick {
  from { transform: translateY(6px); opacity: 0; }
  to   { transform: translateY(0);   opacity: 1; }
}
.echo-count.just-ticked {
  animation: echo-tick 280ms ease-out;
}

/* ── 7. Motion off ─────────────────────────────────────────────────
 * Everything falls back to section 2 — the drawn ripple — because that
 * is the base state. Nothing disappears, nothing collapses into a
 * single overlapping ring.
 *
 * Do not add a reduced-motion "alternative" animation. A still Echo is
 * a complete Echo: playback is announced by the seal-red dot, the word
 * Playing, and the Pause label. Movement is the fourth, redundant
 * carrier — which is also the answer to Android rendering no CSS
 * animation at all.
 *
 * .motion-off is the Settings → Appearance → Motion = Off class, set on
 * <html>. "Always on" omits both and wins over the device preference.
 */
@media (prefers-reduced-motion: reduce) {
  .echo.is-playing { stroke-opacity: 0.16; }
  .echo.is-playing .echo-ring,
  .echo.is-playing .echo-arc,
  .is-listening .mic-glyph,
  .echo-count.just-ticked { animation: none; }
}
html.motion-off .echo.is-playing { stroke-opacity: 0.16; }
html.motion-off .echo.is-playing .echo-ring,
html.motion-off .echo.is-playing .echo-arc,
html.motion-off .is-listening .mic-glyph,
html.motion-off .echo-count.just-ticked { animation: none; }

/* ── Integration ────────────────────────────────────────────────────
 * Not part of motion.css; the rules above are verbatim and unedited.
 *
 * Appearance > Motion = "Always on" has to beat the device preference,
 * and a media query cannot be talked out of applying — so html.motion-on
 * re-states the animations at a higher specificity than section 7's
 * block. "Follow my device" sets neither class.
 *
 * The review progress bar is the app's only other moving thing; it stops
 * with everything else, which the blanket rule used to do for it.
 */
html.motion-on .echo.is-playing { stroke-opacity: 0.234; }
html.motion-on .echo.is-playing .echo-ring,
html.motion-on .echo.is-playing .echo-arc { animation: echo-emanate 2.4s ease-out infinite; }
html.motion-on .echo.is-playing .echo-ring:nth-of-type(2) { animation-delay: 0.6s; }
html.motion-on .echo.is-playing .echo-ring:nth-of-type(3) { animation-delay: 1.2s; }
html.motion-on .echo.is-playing .echo-ring:nth-of-type(4) { animation-delay: 1.8s; }
html.motion-on .echo.is-playing .echo-arc:nth-of-type(2) { animation-delay: 0.8s; }
html.motion-on .echo.is-playing .echo-arc:nth-of-type(3) { animation-delay: 1.6s; }
html.motion-on .is-listening .mic-glyph { animation: echo-listening 1.4s ease-in-out infinite; }
html.motion-on .echo-count.just-ticked { animation: echo-tick 280ms ease-out; }
@media (prefers-reduced-motion: reduce) {
  html:not(.motion-on) #review-progress-bar { transition: none; }
}
html.motion-off #review-progress-bar { transition: none; }

