How to Add Reading Mode in WordPress πŸ“–

WordPress Reading Mode Guide

A busy website layout can make long articles harder to read. Reading Mode gives visitors a cleaner view of your content, with adjustable text sizes and comfortable background colours.

In this tutorial, we’ll use a custom PHP code snippet to add Reading Mode to WordPress, complete with a floating button and dashboard settings.

What Does This Code Snippet Include?

The supplied code adds several useful features:

  • Floating reading button: Position it in any corner.
  • Five colour themes: Paper, Sepia, Sage, Ocean and Night.
  • Text size controls: Readers can adjust text from 16px to 28px.
  • Estimated reading time: Calculated at 220 words per minute.
  • Reading progress: A progress bar and completion percentage.
  • Saved preferences: Theme and text size choices are stored in the visitor’s browser.
  • Shortcode support: Place the reading button manually.

The reader also preserves your website’s font family and keeps the original article content in place.

Step 1: Add the PHP Code Snippet

Back up your website, then open your wp code manager settings.

WP-Code-Insert-Headers-and-Footers

Create a new snippet named β€œCustom Reading Mode” and paste the complete PHP code provided with this tutorial.

<?php
if ( ! defined( 'ABSPATH' ) ) { exit; }

function k2b_rm_defaults() {
    return array(
        'enabled'      => 1,
        'floating'     => 1,
        'auto_posts'   => 1,
        'auto_pages'   => 0,
        'position'     => 'bottom-right',
        'reading_time' => 1,
        'progress'     => 1,
        'size_controls'=> 1,
        'color_picker' => 1,
        'animation'    => 1,
        'default_theme'=> 'paper',
        'default_size' => 18,
    );
}

function k2b_rm_options() {
    $saved = get_option( 'k2b_rm_options', array() );
    return wp_parse_args( is_array( $saved ) ? $saved : array(), k2b_rm_defaults() );
}

function k2b_rm_sanitize_options( $input ) {
    $input = is_array( $input ) ? $input : array();
    $out = k2b_rm_defaults();
    foreach ( array( 'enabled', 'floating', 'auto_posts', 'auto_pages', 'reading_time', 'progress', 'size_controls', 'color_picker', 'animation' ) as $key ) {
        $out[ $key ] = ! empty( $input[ $key ] ) ? 1 : 0;
    }
    $positions = array( 'bottom-right', 'bottom-left', 'top-right', 'top-left' );
    $themes = array( 'paper', 'sepia', 'sage', 'ocean', 'night' );
    $out['position'] = isset( $input['position'] ) && in_array( $input['position'], $positions, true ) ? $input['position'] : 'bottom-right';
    $out['default_theme'] = isset( $input['default_theme'] ) && in_array( $input['default_theme'], $themes, true ) ? $input['default_theme'] : 'paper';
    $out['default_size'] = isset( $input['default_size'] ) && in_array( (int) $input['default_size'], array(16,18,20,22), true ) ? (int) $input['default_size'] : 18;
    return $out;
}

add_action( 'admin_init', function () {
    register_setting( 'k2b_rm_settings_group', 'k2b_rm_options', array(
        'type' => 'array',
        'sanitize_callback' => 'k2b_rm_sanitize_options',
        'default' => k2b_rm_defaults(),
    ) );
} );

add_action( 'admin_menu', function () {
    add_menu_page(
        'Reading Mode Settings', 'Reading Mode', 'manage_options',
        'k2b-reading-mode', 'k2b_rm_settings_screen', 'dashicons-book-alt', 79
    );
} );

// The same book symbol is used on the public button and the dashboard preview.
function k2b_rm_book_icon( $size = 21 ) {
    $size = (int) $size;
    return '<svg width="' . $size . '" height="' . $size . '" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 7v14"/><path d="M3 18V5a2 2 0 0 1 2-2h3a4 4 0 0 1 4 4 4 4 0 0 1 4-4h3a2 2 0 0 1 2 2v13a2 2 0 0 0-2-2h-3a4 4 0 0 0-4 4 4 4 0 0 0-4-4H5a2 2 0 0 0-2 2Z"/></svg>';
}

function k2b_rm_setting_switch( $options, $key, $label, $hint ) {
    ?>
    <label class="k2b-ui-option">
      <span class="k2b-ui-option-text"><strong><?php echo esc_html( $label ); ?></strong><small><?php echo esc_html( $hint ); ?></small></span>
      <span class="k2b-ui-switch">
        <input type="checkbox" name="k2b_rm_options[<?php echo esc_attr( $key ); ?>]" value="1" <?php checked( ! empty( $options[ $key ] ) ); ?> />
        <span class="k2b-ui-switch-track" aria-hidden="true"></span>
      </span>
    </label>
    <?php
}

function k2b_rm_settings_screen() {
    if ( ! current_user_can( 'manage_options' ) ) { return; }
    $o = k2b_rm_options();
    $positions = array( 'top-left' => 'Top left', 'top-right' => 'Top right', 'bottom-left' => 'Bottom left', 'bottom-right' => 'Bottom right' );
    $themes = array(
        'paper' => array( 'Paper', '#ffffff', '#232e3a' ),
        'sepia' => array( 'Sepia', '#f6eddd', '#453429' ),
        'sage' => array( 'Sage', '#eaf4eb', '#263d32' ),
        'ocean' => array( 'Ocean', '#eaf3fb', '#203b52' ),
        'night' => array( 'Night', '#1b2430', '#e9edf4' ),
    );
    ?>
    <div class="wrap k2b-ui">
      <header class="k2b-ui-header">
        <div class="k2b-ui-mark" aria-hidden="true"><?php echo k2b_rm_book_icon( 23 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div>
        <div class="k2b-ui-title"><h1>Reading Mode</h1><p>Simple controls for a better reading experience.</p></div>
        <span class="k2b-ui-status <?php echo ! empty( $o['enabled'] ) ? 'is-enabled' : ''; ?>" id="k2b-ui-status"><span class="k2b-ui-status-dot"></span><span><?php echo ! empty( $o['enabled'] ) ? 'Enabled' : 'Disabled'; ?></span></span>
      </header>
      <?php settings_errors(); ?>
      <form method="post" action="options.php" class="k2b-ui-form">
        <?php settings_fields( 'k2b_rm_settings_group' ); ?>
        <div class="k2b-ui-tabs" role="tablist" aria-label="Reading Mode settings">
          <button type="button" role="tab" id="k2b-tab-display" aria-controls="k2b-panel-display" aria-selected="true" tabindex="0">Display</button>
          <button type="button" role="tab" id="k2b-tab-tools" aria-controls="k2b-panel-tools" aria-selected="false" tabindex="-1">Reader tools</button>
          <button type="button" role="tab" id="k2b-tab-appearance" aria-controls="k2b-panel-appearance" aria-selected="false" tabindex="-1">Appearance</button>
        </div>
        <div class="k2b-ui-layout">
          <main class="k2b-ui-main">
            <section class="k2b-ui-panel" role="tabpanel" aria-labelledby="k2b-tab-display" id="k2b-panel-display" tabindex="0">
              <div class="k2b-ui-section-head"><h2>Button visibility</h2><p>Decide when and where the reading button is shown.</p></div>
              <?php
              k2b_rm_setting_switch( $o, 'enabled', 'Enable Reading Mode', 'Turn the reader on or off everywhere.' );
              k2b_rm_setting_switch( $o, 'floating', 'Floating button', 'Show the button in a corner of the screen.' );
              k2b_rm_setting_switch( $o, 'auto_posts', 'Blog posts', 'Display the floating button on posts.' );
              k2b_rm_setting_switch( $o, 'auto_pages', 'Pages', 'Display the floating button on pages.' );
              ?>
              <div class="k2b-ui-section-divider"></div>
              <div class="k2b-ui-section-head"><h2>Floating position</h2><p>Select one of four corners. The preview updates as you choose.</p></div>
              <div class="k2b-ui-positions">
                <?php foreach ( $positions as $value => $label ) : ?>
                  <label class="k2b-ui-position-option">
                    <input type="radio" name="k2b_rm_options[position]" value="<?php echo esc_attr( $value ); ?>" <?php checked( $o['position'], $value ); ?> />
                    <span class="k2b-ui-position-box <?php echo esc_attr( $value ); ?>" aria-hidden="true"><i></i></span>
                    <span class="k2b-ui-position-name"><?php echo esc_html( $label ); ?></span>
                  </label>
                <?php endforeach; ?>
              </div>
            </section>
            <section class="k2b-ui-panel" role="tabpanel" aria-labelledby="k2b-tab-tools" id="k2b-panel-tools" tabindex="0" hidden>
              <div class="k2b-ui-section-head"><h2>Reader tools</h2><p>Keep the toolbar as minimal as you like.</p></div>
              <?php
              k2b_rm_setting_switch( $o, 'reading_time', 'Estimated reading time', 'Show how many minutes the article may take.' );
              k2b_rm_setting_switch( $o, 'progress', 'Reading progress', 'Show a progress bar and completion percentage.' );
              k2b_rm_setting_switch( $o, 'size_controls', 'Text size', 'Let readers adjust article text size.' );
              k2b_rm_setting_switch( $o, 'color_picker', 'Color switcher', 'Allow visitors to choose one of five themes.' );
              k2b_rm_setting_switch( $o, 'animation', 'Button animation', 'Show a subtle attention animation on page load.' );
              ?>
            </section>
            <section class="k2b-ui-panel" role="tabpanel" aria-labelledby="k2b-tab-appearance" id="k2b-panel-appearance" tabindex="0" hidden>
              <div class="k2b-ui-section-head"><h2>Default reading colors</h2><p>The selected theme is used until a visitor chooses their own.</p></div>
              <div class="k2b-ui-themes">
                <?php foreach ( $themes as $name => $theme ) : ?>
                <label class="k2b-ui-theme-option">
                  <input type="radio" name="k2b_rm_options[default_theme]" value="<?php echo esc_attr( $name ); ?>" <?php checked( $o['default_theme'], $name ); ?> />
                  <span class="k2b-ui-theme-dot" style="--dot-bg:<?php echo esc_attr( $theme[1] ); ?>;--dot-ink:<?php echo esc_attr( $theme[2] ); ?>" aria-hidden="true">Aa</span>
                  <span><?php echo esc_html( $theme[0] ); ?></span>
                </label>
                <?php endforeach; ?>
              </div>
              <div class="k2b-ui-section-divider"></div>
              <div class="k2b-ui-section-head"><h2>Default text size</h2><p>Readability without changing the website's existing font family.</p></div>
              <label class="k2b-ui-select-label" for="k2b-ui-size">Reader text size</label>
              <select id="k2b-ui-size" name="k2b_rm_options[default_size]" class="k2b-ui-select">
              <?php foreach ( array( 16, 18, 20, 22 ) as $size ) : ?>
                <option value="<?php echo esc_attr( $size ); ?>" <?php selected( (int) $o['default_size'], $size ); ?>><?php echo esc_html( $size ); ?> px</option>
              <?php endforeach; ?>
              </select>
              <p class="k2b-ui-footnote">The reader inherits the original site font family. Visitors' saved preferences take priority when the corresponding control is enabled.</p>
            </section>
          </main>
          <aside class="k2b-ui-aside" aria-label="Preview and shortcode">
            <section class="k2b-ui-preview-card">
              <div class="k2b-ui-aside-head"><h2>Live preview</h2><span>Button placement</span></div>
              <div class="k2b-ui-browser" id="k2b-ui-browser" data-position="<?php echo esc_attr( $o['position'] ); ?>" data-theme="<?php echo esc_attr( $o['default_theme'] ); ?>">
                <div class="k2b-ui-browser-bar"><i></i><i></i><i></i><b></b></div>
                <div class="k2b-ui-browser-page">
                  <div class="k2b-ui-browser-article"><span class="k2b-ui-mock-title"></span><span class="k2b-ui-mock-line long"></span><span class="k2b-ui-mock-line"></span><span class="k2b-ui-mock-line short"></span><span class="k2b-ui-mock-line long"></span></div>
                  <div class="k2b-ui-browser-fab" aria-label="Reading Mode button preview"><?php echo k2b_rm_book_icon( 20 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div>
                </div>
              </div>
              <p class="k2b-ui-footnote">The public button keeps its original open-book icon and circular style.</p>
            </section>
            <section class="k2b-ui-shortcode-card">
              <div class="k2b-ui-aside-head"><h2>Shortcode</h2><span>Manual placement</span></div>
              <div class="k2b-ui-copy-field"><input id="k2b-ui-shortcode" readonly value="[k2b_reading_mode]" aria-label="Reading Mode shortcode" /><button type="button" class="button" id="k2b-ui-copy" aria-label="Copy shortcode">Copy</button></div>
              <p class="k2b-ui-footnote">Use a Shortcode block or widget. You can disable the floating button and use only the shortcode. The main Enable switch must stay on.</p>
            </section>
          </aside>
        </div>
        <div class="k2b-ui-actions">
          <span id="k2b-ui-dirty" aria-live="polite">Configure your preferences and save.</span>
          <?php submit_button( 'Save changes', 'primary', 'submit', false ); ?>
        </div>
      </form>
      <footer class="k2b-ui-credit">Made with <svg viewBox="0 0 24 24" width="15" height="15" fill="currentColor" aria-hidden="true"><path d="M20.8 4.6a5.5 5.5 0 0 0-7.8 0L12 5.7l-1.1-1.1a5.5 5.5 0 0 0-7.8 7.8L12 21l8.8-8.6a5.5 5.5 0 0 0 0-7.8Z"/></svg> by <a href="https://key2blogging.com" target="_blank" rel="noopener noreferrer">Key2Blogging</a></footer>
    </div>
    <?php
}

add_action( 'admin_enqueue_scripts', function ( $hook ) {
    if ( 'toplevel_page_k2b-reading-mode' !== $hook ) { return; }
    wp_register_style( 'k2b-rm-admin', false, array(), '1.4.0' );
    wp_enqueue_style( 'k2b-rm-admin' );
    wp_add_inline_style( 'k2b-rm-admin', <<<'ADMINCSS'
/* Compact settings UI; scoped to Reading Mode screen only. */
.k2b-ui{--kb-blue:#2563eb;--kb-ink:#1e293b;--kb-muted:#64748b;--kb-line:#e2e8f0;max-width:1050px;margin:25px 24px 35px 0;color:var(--kb-ink)}
.k2b-ui *{box-sizing:border-box}.k2b-ui-header{display:flex;align-items:center;gap:13px;margin:0 0 22px}
.k2b-ui-mark{width:48px;height:48px;flex:none;border-radius:13px;background:#eaf2ff;color:#2563eb;display:grid;place-items:center}
.k2b-ui-mark svg,.k2b-ui-browser-fab svg{display:block;stroke:currentColor;fill:none}
.k2b-ui-title{flex:1;min-width:0}.k2b-ui-title h1{padding:0;margin:0 0 3px;color:#17263b;font-size:25px;line-height:1.2;font-weight:750}
.k2b-ui-title p{margin:0;color:#748196;font-size:13px;line-height:1.4}
.k2b-ui-status{display:inline-flex;align-items:center;gap:7px;border:1px solid #d9e1eb;border-radius:999px;background:#f1f5f9;padding:7px 12px;font-size:12px;font-weight:650;color:#64748b}
.k2b-ui-status-dot{height:7px;width:7px;border-radius:50%;background:#94a3b8}.k2b-ui-status.is-enabled{color:#147651;background:#e9f9f0;border-color:#bfe8d2}.k2b-ui-status.is-enabled .k2b-ui-status-dot{background:#19a46a}
.k2b-ui-tabs{display:flex;gap:3px;border-bottom:1px solid #dce3ed;margin-bottom:15px}
.k2b-ui-tabs button{position:relative;margin:0;background:transparent;border:0;padding:12px 18px;color:#64748b;font-size:13px;font-weight:650;cursor:pointer;border-radius:7px 7px 0 0}
.k2b-ui-tabs button:hover{color:#1d4e91;background:#edf4ff}.k2b-ui-tabs button[aria-selected=true]{color:#1d63ce}
.k2b-ui-tabs button[aria-selected=true]:after{content:"";position:absolute;bottom:-1px;height:3px;left:8px;right:8px;border-radius:3px;background:#2b71d4}
.k2b-ui button:focus-visible,.k2b-ui input:focus-visible,.k2b-ui select:focus-visible,.k2b-ui label:focus-within{outline-offset:2px}
.k2b-ui-layout{display:grid;grid-template-columns:minmax(0,1fr) 300px;gap:17px;align-items:start}
.k2b-ui-main,.k2b-ui-preview-card,.k2b-ui-shortcode-card{border:1px solid #dfe5ed;background:#fff;border-radius:13px;box-shadow:0 2px 7px #162c4609}
.k2b-ui-main{min-width:0}.k2b-ui-panel{padding:24px 25px 27px;min-height:377px}.k2b-ui-panel[hidden]{display:none!important}
.k2b-ui-section-head{margin-bottom:14px}.k2b-ui-section-head h2{padding:0;margin:0 0 4px;font-size:15px;font-weight:700;line-height:1.3;color:#243047}
.k2b-ui-section-head p{font-size:12.5px;line-height:1.5;margin:0;color:#8290a2}
.k2b-ui-option{display:flex;gap:15px;align-items:center;justify-content:space-between;cursor:pointer;padding:11px 0;border-bottom:1px solid #eff2f6}
.k2b-ui-option:last-child{border-bottom:0}.k2b-ui-option-text{display:grid;gap:3px;min-width:0}.k2b-ui-option-text strong{font-size:13px;font-weight:650;line-height:1.3;color:#29384d}
.k2b-ui-option-text small{color:#8190a2;font-size:12px;line-height:1.4}.k2b-ui-switch{flex:none;position:relative;width:40px;height:23px}
.k2b-ui-switch input{position:absolute;inset:0;opacity:0;z-index:2;width:100%;height:100%;margin:0;cursor:pointer}
.k2b-ui-switch-track{pointer-events:none;position:absolute;inset:0;background:#cbd5e1;border-radius:999px;transition:background .17s}
.k2b-ui-switch-track:after{content:"";position:absolute;left:3px;top:3px;width:17px;height:17px;background:#fff;border-radius:50%;box-shadow:0 1px 2px #0002;transition:transform .17s}
.k2b-ui-switch input:checked+.k2b-ui-switch-track{background:var(--kb-blue)}.k2b-ui-switch input:checked+.k2b-ui-switch-track:after{transform:translateX(17px)}
.k2b-ui-switch input:focus-visible+.k2b-ui-switch-track{outline:3px solid #a1c1ff;outline-offset:2px}
.k2b-ui-section-divider{margin:20px 0 19px;border-top:1px solid #e7ecf2}
.k2b-ui-positions{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}
.k2b-ui-position-option{display:flex;flex-direction:column;align-items:center;gap:8px;position:relative;cursor:pointer;padding:12px 4px 11px;border:1px solid #dce4ee;border-radius:9px;background:#fff;color:#6b7b8d}
.k2b-ui-position-option input{position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:pointer;z-index:1}
.k2b-ui-position-option:has(input:checked){border-color:#4684d8;background:#eff6ff;box-shadow:inset 0 0 0 1px #4684d8;color:#22559b}
.k2b-ui-position-option:has(input:focus-visible){outline:3px solid #98bdf6;outline-offset:2px}
.k2b-ui-position-box{position:relative;width:44px;height:28px;background:#f8fafc;border:1px solid #c8d4e1;border-radius:5px}
.k2b-ui-position-box i{position:absolute;background:#367ed4;border-radius:50%;width:8px;height:8px}
.k2b-ui-position-box.top-left i{left:3px;top:3px}.k2b-ui-position-box.top-right i{right:3px;top:3px}.k2b-ui-position-box.bottom-left i{left:3px;bottom:3px}.k2b-ui-position-box.bottom-right i{right:3px;bottom:3px}
.k2b-ui-position-name{font-size:11px;line-height:1.3;text-align:center;font-weight:600}
.k2b-ui-themes{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:9px}
.k2b-ui-theme-option{position:relative;display:flex;flex-direction:column;align-items:center;gap:8px;cursor:pointer;background:#fff;border:1px solid #dfe5ed;border-radius:10px;padding:15px 5px 12px;text-align:center;color:#536174;font-size:12px;font-weight:600}
.k2b-ui-theme-option input{position:absolute;inset:0;opacity:0;width:100%;height:100%;z-index:1;margin:0;cursor:pointer}
.k2b-ui-theme-dot{width:33px;height:33px;border-radius:50%;display:grid;place-items:center;background:var(--dot-bg);color:var(--dot-ink);border:1px solid #cbd5e1;font-size:12px;font-weight:750}
.k2b-ui-theme-option:has(input:checked){border-color:#4684d8;background:#eff6ff;box-shadow:inset 0 0 0 1px #4684d8}
.k2b-ui-theme-option:has(input:focus-visible){outline:3px solid #98bdf6;outline-offset:2px}
.k2b-ui-select-label{display:block;margin:0 0 8px;font-size:12px;font-weight:650;color:#475569}.k2b-ui-select{max-width:180px;width:100%;height:36px;border-color:#cbd5e1!important;border-radius:7px!important}
.k2b-ui-footnote{font-size:11.5px;line-height:1.5;color:#8794a6;margin:12px 0 0}
.k2b-ui-aside{display:grid;gap:13px;min-width:0}.k2b-ui-preview-card,.k2b-ui-shortcode-card{padding:17px 18px 19px}
.k2b-ui-aside-head{display:flex;align-items:center;justify-content:space-between;gap:6px;margin-bottom:13px}.k2b-ui-aside-head h2{font-size:13px;font-weight:700;margin:0;padding:0;color:#243047}.k2b-ui-aside-head span{font-size:11px;color:#94a3b8}
.k2b-ui-browser{border:1px solid #d9e0e9;border-radius:9px;overflow:hidden;background:#fff;--preview-bg:#fff;--preview-fg:#243041}
.k2b-ui-browser[data-theme=sepia]{--preview-bg:#f6eddd;--preview-fg:#453429}.k2b-ui-browser[data-theme=sage]{--preview-bg:#eaf4eb;--preview-fg:#263d32}.k2b-ui-browser[data-theme=ocean]{--preview-bg:#eaf3fb;--preview-fg:#203b52}.k2b-ui-browser[data-theme=night]{--preview-bg:#1b2430;--preview-fg:#e9edf4}
.k2b-ui-browser-bar{display:flex;gap:4px;align-items:center;height:25px;border-bottom:1px solid #e2e8f0;background:#f8fafc;padding:0 9px}
.k2b-ui-browser-bar i{height:5px;width:5px;border-radius:50%;background:#cbd5e1}.k2b-ui-browser-bar b{width:40%;height:10px;border-radius:4px;background:#e4eaf1;margin:auto}
.k2b-ui-browser-page{height:145px;position:relative;background:var(--preview-bg);color:var(--preview-fg);padding:23px 32px}
.k2b-ui-browser-article{display:grid;gap:7px;max-width:180px;margin:auto}.k2b-ui-mock-title{height:9px;width:72%;border-radius:3px;background:currentColor;opacity:.8;margin-bottom:8px}
.k2b-ui-mock-line{display:block;height:5px;border-radius:3px;width:85%;background:currentColor;opacity:.18}.k2b-ui-mock-line.long{width:100%}.k2b-ui-mock-line.short{width:62%}
.k2b-ui-browser-fab{position:absolute;display:grid;place-items:center;width:32px;height:32px;border:1px solid #d7e2ee;box-shadow:0 3px 10px #102b4924;background:#fff;color:#245188;border-radius:50%;right:12px;bottom:12px;transition:inset .13s}
.k2b-ui-browser[data-position=bottom-left] .k2b-ui-browser-fab{right:auto;left:12px}.k2b-ui-browser[data-position=top-right] .k2b-ui-browser-fab{bottom:auto;top:10px}.k2b-ui-browser[data-position=top-left] .k2b-ui-browser-fab{right:auto;left:12px;bottom:auto;top:10px}
.k2b-ui-copy-field{display:flex;gap:7px}.k2b-ui-copy-field input{width:100%;flex:1;min-width:0;border-radius:7px;background:#f8fafc;border:1px solid #d7e0e9;font-family:monospace;font-size:12px;padding:7px 9px;color:#334155}
.k2b-ui-copy-field .button{border-radius:7px;min-height:35px}
.k2b-ui-actions{position:relative;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:16px 0;margin-top:2px;border-bottom:1px solid #dee5ed}
.k2b-ui-actions span{color:#94a3b8;font-size:12px}.k2b-ui-actions .button-primary{margin:0!important;border-radius:7px;min-height:39px;padding:4px 19px;background:#236bd1;border-color:#236bd1;font-weight:650}
.k2b-ui-credit{display:flex;align-items:center;justify-content:center;gap:4px;color:#8794a6;padding:17px 0;font-size:12px}.k2b-ui-credit svg{color:#eb546b}.k2b-ui-credit a{color:#2563a7;font-weight:700;text-decoration:none}.k2b-ui-credit a:hover{text-decoration:underline}
@media(max-width:850px){.k2b-ui-layout{grid-template-columns:1fr}.k2b-ui-aside{grid-template-columns:1fr 1fr}.k2b-ui-panel{min-height:auto}}
@media(max-width:620px){.k2b-ui{margin:15px 14px 24px 0}.k2b-ui-header{flex-wrap:wrap}.k2b-ui-title h1{font-size:22px}.k2b-ui-status{margin-left:0}.k2b-ui-tabs button{padding:12px 10px;font-size:12px}.k2b-ui-panel{padding:18px 16px}.k2b-ui-aside{grid-template-columns:1fr}.k2b-ui-positions{grid-template-columns:repeat(2,minmax(0,1fr))}.k2b-ui-themes{grid-template-columns:repeat(3,minmax(0,1fr))}.k2b-ui-actions{flex-wrap:wrap}}
@media(prefers-reduced-motion:reduce){.k2b-ui-switch-track,.k2b-ui-switch-track:after,.k2b-ui-browser-fab{transition:none}}
ADMINCSS
    );
    wp_register_script( 'k2b-rm-admin', false, array(), '1.4.0', true );
    wp_enqueue_script( 'k2b-rm-admin' );
    wp_add_inline_script( 'k2b-rm-admin', <<<'ADMINJS'
(function(){
  'use strict';
  var root=document.querySelector('.k2b-ui');
  if(!root)return;
  var tabs=Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
  function selectTab(tab,focus){
    tabs.forEach(function(t){
      var active=t===tab;
      t.setAttribute('aria-selected',String(active));
      t.tabIndex=active?0:-1;
      var panel=document.getElementById(t.getAttribute('aria-controls'));
      if(panel)panel.hidden=!active;
    });
    if(focus)tab.focus();
  }
  tabs.forEach(function(tab,i){
    tab.addEventListener('click',function(){selectTab(tab,false)});
    tab.addEventListener('keydown',function(event){
      var next;
      if(event.key==='ArrowRight')next=(i+1)%tabs.length;
      else if(event.key==='ArrowLeft')next=(i+tabs.length-1)%tabs.length;
      else if(event.key==='Home')next=0;
      else if(event.key==='End')next=tabs.length-1;
      else return;
      event.preventDefault();selectTab(tabs[next],true);
    });
  });
  var browser=root.querySelector('#k2b-ui-browser');
  var status=root.querySelector('#k2b-ui-status');
  var statusText=status.querySelector('span:last-child');
  var dirty=root.querySelector('#k2b-ui-dirty');
  var form=root.querySelector('form');
  function updatePreview(){
    var pos=form.querySelector('input[name="k2b_rm_options[position]"]:checked');
    var theme=form.querySelector('input[name="k2b_rm_options[default_theme]"]:checked');
    var enabled=form.querySelector('input[name="k2b_rm_options[enabled]"]');
    if(pos)browser.dataset.position=pos.value;
    if(theme)browser.dataset.theme=theme.value;
    status.classList.toggle('is-enabled',enabled.checked);
    statusText.textContent=enabled.checked?'Enabled':'Disabled';
  }
  form.addEventListener('change',function(){updatePreview();dirty.textContent='Unsaved changes';});
  updatePreview();
  var copy=root.querySelector('#k2b-ui-copy');
  var field=root.querySelector('#k2b-ui-shortcode');
  copy.addEventListener('click',function(){
    function fallback(){field.focus();field.select();copy.textContent='Select & copy';}
    if(!navigator.clipboard||!navigator.clipboard.writeText){fallback();return;}
    navigator.clipboard.writeText(field.value).then(function(){
      copy.textContent='Copied';
    },fallback);
  });
}());
ADMINJS
    );
} );

// Available on standard singular posts/pages. Manual shortcode still works if auto-floating is disabled.
function k2b_rm_page_enabled() {
    $o = k2b_rm_options();
    return ! is_admin() && ! is_feed() && ! empty( $o['enabled'] ) && is_singular( array( 'post', 'page' ) );
}

function k2b_rm_button( $type = 'shortcode' ) {
    $o = k2b_rm_options();
    $classes = 'k2b-rm-launch-wrap ';
    $classes .= 'floating' === $type ? 'k2b-rm-floating k2b-rm-position-' . $o['position'] : 'k2b-rm-shortcode';
    if ( ! empty( $o['animation'] ) ) { $classes .= ' k2b-rm-animate'; }
    return '<span class="' . esc_attr( $classes ) . '"><button type="button" class="k2b-rm-launch" aria-label="Open reading mode" aria-pressed="false" title="Reading mode"><svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 7v14"/><path d="M3 18V5a2 2 0 0 1 2-2h3a4 4 0 0 1 4 4 4 4 0 0 1 4-4h3a2 2 0 0 1 2 2v13a2 2 0 0 0-2-2h-3a4 4 0 0 0-4-4H5a2 2 0 0 0-2 2Z"/></svg></button></span>';
}

add_shortcode( 'k2b_reading_mode', function() {
    return k2b_rm_page_enabled() ? k2b_rm_button( 'shortcode' ) : '';
} );

add_filter( 'the_content', function( $content ) {
    if ( ! k2b_rm_page_enabled() || ! in_the_loop() || ! is_main_query() ) { return $content; }
    $id = get_the_ID();
    if ( (int) $id !== (int) get_queried_object_id() || strpos( $content, 'data-k2b-rm-start' ) !== false ) { return $content; }
    return '<span data-k2b-rm-start hidden></span>'
      . '<h1 class="k2b-rm-post-title" hidden>' . esc_html( get_the_title( $id ) ) . '</h1>'
      . $content
      . '<span data-k2b-rm-end hidden></span>';
}, 99 );

add_action( 'wp_footer', function () {
    if ( ! k2b_rm_page_enabled() ) { return; }
    $o = k2b_rm_options();
    $auto = ! empty( $o['floating'] ) && ( ( is_singular( 'post' ) && ! empty( $o['auto_posts'] ) ) || ( is_singular( 'page' ) && ! empty( $o['auto_pages'] ) ) );
    // If the shortcode is in the post body, use the manual button instead of duplicating it.
    $post_id = get_queried_object_id();
    if ( $auto && $post_id && has_shortcode( (string) get_post_field( 'post_content', $post_id ), 'k2b_reading_mode' ) ) {
        $auto = false;
    }
    if ( $auto ) { echo k2b_rm_button( 'floating' ); /* phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped */ }
    ?>
    <div id="k2b-rm-toolbar" class="k2b-rm-toolbar" role="toolbar" aria-label="Reading mode controls"
         data-default-theme="<?php echo esc_attr( $o['default_theme'] ); ?>" data-default-size="<?php echo esc_attr( $o['default_size'] ); ?>" hidden>
      <div class="k2b-rm-toolbar-inner">
        <div class="k2b-rm-overview">
          <svg width="19" height="19" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 7v14"/><path d="M3 18V5a2 2 0 0 1 2-2h3a4 4 0 0 1 4-4h3a2 2 0 0 1 2 2v13a2 2 0 0 0-2-2h-3a4 4 0 0 0-4 4 4 4 0 0 0-4-4H5a2 2 0 0 0-2 2Z"/></svg>
          <strong>Reading mode</strong>
          <span class="k2b-rm-meta" <?php if ( empty( $o['reading_time'] ) && empty( $o['progress'] ) ) { echo 'hidden'; } ?>>
            <span data-k2b-rm-time <?php if ( empty( $o['reading_time'] ) ) { echo 'hidden'; } ?>>1 min read</span>
            <span class="k2b-rm-meta-sep" aria-hidden="true" <?php if ( empty( $o['reading_time'] ) || empty( $o['progress'] ) ) { echo 'hidden'; } ?>>Β·</span>
            <span data-k2b-rm-percent <?php if ( empty( $o['progress'] ) ) { echo 'hidden'; } ?>>0%</span>
          </span>
        </div>
        <div class="k2b-rm-controls">
          <button type="button" data-k2b-rm-smaller aria-label="Make article text smaller" title="Smaller text" <?php if ( empty( $o['size_controls'] ) ) { echo 'hidden'; } ?>>Aβˆ’</button>
          <output data-k2b-rm-size aria-label="Current text size" <?php if ( empty( $o['size_controls'] ) ) { echo 'hidden'; } ?>>18px</output>
          <button type="button" data-k2b-rm-larger aria-label="Make article text larger" title="Larger text" <?php if ( empty( $o['size_controls'] ) ) { echo 'hidden'; } ?>>A+</button>
          <span class="k2b-rm-divider" aria-hidden="true" <?php if ( empty( $o['size_controls'] ) || empty( $o['color_picker'] ) ) { echo 'hidden'; } ?>></span>
          <button type="button" data-k2b-rm-palette aria-label="Choose reading color scheme" aria-expanded="false" aria-controls="k2b-rm-colors" title="Change reading colors" <?php if ( empty( $o['color_picker'] ) ) { echo 'hidden'; } ?>><span class="k2b-rm-color-wheel" aria-hidden="true"></span><span class="k2b-rm-color-label">Colors</span><svg class="k2b-rm-color-caret" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg></button>
          <button type="button" data-k2b-rm-exit class="k2b-rm-exit" aria-label="Exit reading mode" title="Exit reading mode"><svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg><span>Exit</span></button>
        </div>
      </div>
      <div id="k2b-rm-colors" class="k2b-rm-palette" role="group" aria-label="Choose a reading color theme" hidden>
        <div class="k2b-rm-palette-heading">Reading colors</div>
        <div class="k2b-rm-swatches">
          <button type="button" data-k2b-rm-color="paper" aria-pressed="true"><i style="--swatch:#ffffff;--swatch-ink:#202735" aria-hidden="true"></i>Paper</button>
          <button type="button" data-k2b-rm-color="sepia" aria-pressed="false"><i style="--swatch:#f6eddd;--swatch-ink:#4b3728" aria-hidden="true"></i>Sepia</button>
          <button type="button" data-k2b-rm-color="sage" aria-pressed="false"><i style="--swatch:#eaf4eb;--swatch-ink:#263e32" aria-hidden="true"></i>Sage</button>
          <button type="button" data-k2b-rm-color="ocean" aria-pressed="false"><i style="--swatch:#eaf3fb;--swatch-ink:#203b52" aria-hidden="true"></i>Ocean</button>
          <button type="button" data-k2b-rm-color="night" aria-pressed="false"><i style="--swatch:#1b2430;--swatch-ink:#e9edf4" aria-hidden="true"></i>Night</button>
        </div>
      </div>
      <div class="k2b-rm-progress" role="progressbar" aria-label="Article reading progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0" <?php if ( empty( $o['progress'] ) ) { echo 'hidden'; } ?>><span data-k2b-rm-fill></span></div>
    </div>
    <?php
}, 20 );

add_action( 'wp_enqueue_scripts', function () {
    if ( ! k2b_rm_page_enabled() ) { return; }
    wp_register_style( 'k2b-reading-mode', false, array(), '1.4.0' );
    wp_enqueue_style( 'k2b-reading-mode' );
    wp_add_inline_style( 'k2b-reading-mode', <<<'CSS'
/* Original v1.2 open-book button, with optional corner placement and shortcode use. */
.k2b-rm-launch-wrap{display:inline-flex;vertical-align:middle;position:relative;z-index:9998;line-height:1}
.k2b-rm-floating{position:fixed;z-index:9998}
.k2b-rm-position-bottom-right{right:22px;bottom:calc(24px + env(safe-area-inset-bottom))}
.k2b-rm-position-bottom-left{left:22px;bottom:calc(24px + env(safe-area-inset-bottom))}
.k2b-rm-position-top-right{right:22px;top:22px}
.k2b-rm-position-top-left{left:22px;top:22px}
body.admin-bar .k2b-rm-position-top-right,body.admin-bar .k2b-rm-position-top-left{top:calc(22px + 32px)}
@media(max-width:782px){body.admin-bar .k2b-rm-position-top-right,body.admin-bar .k2b-rm-position-top-left{top:calc(22px + 46px)}}
.k2b-rm-position-bottom-left .k2b-rm-launch:after,.k2b-rm-position-top-left .k2b-rm-launch:after{left:55px;right:auto}
.k2b-rm-launch-wrap.k2b-rm-shortcode{position:relative;margin:0 3px}

.k2b-rm-launch{appearance:none;-webkit-appearance:none;display:grid;place-items:center;width:46px;height:46px;padding:0!important;margin:0!important;border:1px solid #d7e2ee!important;border-radius:50%!important;background:#fff!important;color:#245188!important;box-shadow:0 6px 24px #102b4930!important;cursor:pointer;transition:transform .18s,box-shadow .18s;animation:none}
.k2b-rm-launch svg{display:block!important;width:21px!important;height:21px!important;max-width:none!important;fill:none!important;stroke:currentColor!important;stroke-width:1.8!important;flex-shrink:0!important}
.k2b-rm-launch svg path{fill:none!important;stroke:currentColor!important;stroke-width:1.8!important;stroke-linecap:round!important;stroke-linejoin:round!important}
.k2b-rm-animate .k2b-rm-launch{animation:k2b-rm-nudge 1.6s ease-in-out 3}
.k2b-rm-launch:hover{transform:translateY(-3px);box-shadow:0 8px 26px #102b4940!important}
.k2b-rm-launch:focus-visible,#k2b-rm-toolbar button:focus-visible{outline:3px solid #3588df!important;outline-offset:3px!important}
.k2b-rm-launch:after{content:"Reading mode";position:absolute;right:55px;top:50%;transform:translateY(-50%);white-space:nowrap;background:#192638;color:#fff;padding:7px 10px;border-radius:7px;font:500 12px/1.3 system-ui,sans-serif;opacity:0;visibility:hidden;transition:opacity .15s;pointer-events:none}
.k2b-rm-launch:hover:after,.k2b-rm-launch:focus-visible:after{opacity:1;visibility:visible}
@keyframes k2b-rm-nudge{50%{box-shadow:0 0 0 9px #347dc526,0 6px 24px #102b4930}}

/* Only affect the page while reading mode is active */
html.k2b-rm-active{scroll-behavior:auto!important;margin-top:0!important;overflow-x:hidden!important}
body.k2b-rm-active{--rm-bg:#ffffff;--rm-fg:#202735;--rm-muted:#5b6574;--rm-link:#125db0;--rm-border:#e3e8ed;--rm-panel:#f9fafb;--rm-size:18px;--rm-width:760px;--rm-top:70px;background:var(--rm-bg)!important;color:var(--rm-fg)!important;margin:0!important;padding:var(--rm-top) 0 0!important;min-height:100vh!important;overflow-x:hidden!important}
body.k2b-rm-active[data-k2b-rm-theme="sepia"]{--rm-bg:#f6eddd;--rm-fg:#453429;--rm-muted:#746252;--rm-link:#805028;--rm-border:#e3d5bf;--rm-panel:#fbf3e6}
body.k2b-rm-active[data-k2b-rm-theme="sage"]{--rm-bg:#eaf4eb;--rm-fg:#263d32;--rm-muted:#526c5c;--rm-link:#176a54;--rm-border:#c9dfd0;--rm-panel:#f2f9f3}
body.k2b-rm-active[data-k2b-rm-theme="ocean"]{--rm-bg:#eaf3fb;--rm-fg:#203b52;--rm-muted:#54728b;--rm-link:#11639e;--rm-border:#cbdfed;--rm-panel:#f4f9fd}
body.k2b-rm-active[data-k2b-rm-theme="night"]{--rm-bg:#1b2430;--rm-fg:#e9edf4;--rm-muted:#b3bfce;--rm-link:#9ccaff;--rm-border:#3b4b5b;--rm-panel:#283443;color-scheme:dark}
/* Maintain original article nodes and all its ads; collapse only surrounding theme containers. */
body.k2b-rm-active>:not(.k2b-rm-path):not(#k2b-rm-toolbar){display:none!important}
body.k2b-rm-active .k2b-rm-path:not(.k2b-rm-content)>:not(.k2b-rm-path){display:none!important}
body.k2b-rm-active .k2b-rm-path:not(.k2b-rm-content){display:block!important;position:static!important;inset:auto!important;float:none!important;transform:none!important;max-width:none!important;min-width:0!important;width:100%!important;height:auto!important;min-height:0!important;overflow:visible!important;margin:0!important;padding:0!important;border:0!important;box-shadow:none!important;background:transparent!important;grid-template-columns:none!important;flex:none!important}
body.k2b-rm-active .k2b-rm-path:not(.k2b-rm-content):before,body.k2b-rm-active .k2b-rm-path:not(.k2b-rm-content):after{display:none!important}
body.k2b-rm-active .k2b-rm-excluded,body.k2b-rm-active .k2b-rm-launch-wrap{display:none!important}
body.k2b-rm-active .k2b-rm-content{box-sizing:border-box!important;display:block!important;position:relative!important;transform:none!important;float:none!important;width:calc(100% - 38px)!important;max-width:var(--rm-width)!important;min-width:0!important;height:auto!important;min-height:0!important;overflow:visible!important;margin:0 auto!important;padding:28px 0 90px!important;background:transparent!important;border:0!important;box-shadow:none!important;color:var(--rm-fg)!important;font-family:var(--rm-font-body,inherit)!important;font-size:var(--rm-size)!important;line-height:1.8!important;text-align:left!important}
body.k2b-rm-active .k2b-rm-content :is(p,li,blockquote,figcaption,td,th,dd,dt){font-family:var(--rm-font-body,inherit)!important;font-size:var(--rm-size)!important;line-height:1.8!important;color:var(--rm-fg)!important}
body.k2b-rm-active .k2b-rm-content :is(p,li,blockquote,figcaption,td,th){background-color:transparent!important}
body.k2b-rm-active .k2b-rm-content :is(h1,h2,h3,h4,h5,h6){font-weight:700!important;line-height:1.33!important;color:var(--rm-fg)!important;letter-spacing:normal!important}
body.k2b-rm-active .k2b-rm-content h1{font-family:var(--rm-font-h1,var(--rm-font-heading,var(--rm-font-body,inherit)))!important;font-size:calc(var(--rm-size)*1.95)!important}
body.k2b-rm-active .k2b-rm-content h2{font-family:var(--rm-font-h2,var(--rm-font-heading,var(--rm-font-body,inherit)))!important;font-size:calc(var(--rm-size)*1.58)!important}
body.k2b-rm-active .k2b-rm-content h3{font-family:var(--rm-font-h3,var(--rm-font-heading,var(--rm-font-body,inherit)))!important;font-size:calc(var(--rm-size)*1.3)!important}
body.k2b-rm-active .k2b-rm-content :is(h4,h5,h6){font-size:calc(var(--rm-size)*1.12)!important}
body.k2b-rm-active .k2b-rm-content h4{font-family:var(--rm-font-h4,var(--rm-font-heading,inherit))!important}
body.k2b-rm-active .k2b-rm-content h5{font-family:var(--rm-font-h5,var(--rm-font-heading,inherit))!important}
body.k2b-rm-active .k2b-rm-content h6{font-family:var(--rm-font-h6,var(--rm-font-heading,inherit))!important}
body.k2b-rm-active .k2b-rm-content a{color:var(--rm-link)!important;text-decoration:underline;text-underline-offset:2px}
body.k2b-rm-active .k2b-rm-content :is(img,video){max-width:100%!important;height:auto}
body.k2b-rm-active .k2b-rm-content iframe{max-width:100%!important}
body.k2b-rm-active .k2b-rm-content :is(.alignwide,.alignfull){max-width:100%!important;width:100%!important;margin-left:0!important;margin-right:0!important}
body.k2b-rm-active .k2b-rm-content blockquote{border-left:3px solid var(--rm-link)!important;padding-left:18px!important;margin-left:0!important}
body.k2b-rm-active .k2b-rm-content :is(pre,code){overflow-wrap:anywhere}
body.k2b-rm-active .k2b-rm-content pre{overflow-x:auto!important;border-radius:10px!important;padding:18px!important;background:var(--rm-panel)!important;color:var(--rm-fg)!important;border:1px solid var(--rm-border)!important}
body.k2b-rm-active .k2b-rm-content :is(.sharedaddy,.addtoany_share_save_container,.wp-block-social-links,.related-posts){display:none!important}
.k2b-rm-post-title[hidden]{display:none!important}
body.k2b-rm-active .k2b-rm-post-title:not([hidden]){display:block!important;margin:8px 0 30px!important;padding:0!important}

/* Toolbar, reading time, progress, and color picker */
#k2b-rm-toolbar[hidden],#k2b-rm-colors[hidden],#k2b-rm-toolbar [hidden]{display:none!important}
#k2b-rm-toolbar{box-sizing:border-box;position:fixed;top:0;left:0;right:0;z-index:2147483647;background:var(--rm-panel);color:var(--rm-fg);border-bottom:1px solid var(--rm-border);font:500 14px/1.4 var(--rm-font-body,system-ui,sans-serif);box-shadow:0 3px 15px #0000000a}
#k2b-rm-toolbar *{box-sizing:border-box}
.k2b-rm-toolbar-inner{min-height:65px;max-width:1150px;padding:10px 20px;margin:0 auto;display:flex;align-items:center;justify-content:space-between;gap:12px}
.k2b-rm-overview{display:flex;align-items:center;gap:9px;min-width:0;white-space:nowrap}
.k2b-rm-overview strong{font-size:14px;font-weight:700}
.k2b-rm-meta{display:inline-flex;align-items:center;gap:7px;color:var(--rm-muted);font-size:12px;margin-left:6px}
.k2b-rm-controls{display:flex;align-items:center;gap:6px}
#k2b-rm-toolbar button{display:inline-flex;justify-content:center;align-items:center;gap:7px;min-width:37px;min-height:36px;padding:0 10px;margin:0;background:transparent;color:var(--rm-fg);border:1px solid transparent;border-radius:8px;cursor:pointer;font:600 14px/1.2 var(--rm-font-body,system-ui,sans-serif);text-transform:none;box-shadow:none;white-space:nowrap}
#k2b-rm-toolbar button:hover{background:var(--rm-bg);border-color:var(--rm-border)}
#k2b-rm-toolbar button:disabled{opacity:.45;cursor:not-allowed}
.k2b-rm-controls output{min-width:38px;text-align:center;color:var(--rm-muted);font-size:12px}
.k2b-rm-divider{height:23px;border-left:1px solid var(--rm-border);margin:0 5px}
/* Recognizable multicolor scheme-picker control (works in every reading theme). */
#k2b-rm-toolbar [data-k2b-rm-palette]{gap:7px;min-height:39px;padding:0 10px;background:var(--rm-bg);border:1px solid var(--rm-border);border-radius:10px;font-weight:700}
#k2b-rm-toolbar [data-k2b-rm-palette]:hover{border-color:var(--rm-link);background:var(--rm-bg)}
#k2b-rm-toolbar [data-k2b-rm-palette][aria-expanded="true"]{border-color:var(--rm-link);box-shadow:0 0 0 1px var(--rm-link)}
.k2b-rm-color-wheel{position:relative;display:block;flex:0 0 22px;width:22px;height:22px;border-radius:50%;background:conic-gradient(#f26a65 0deg 60deg,#f0b846 60deg 120deg,#52ad72 120deg 180deg,#43a6c9 180deg 240deg,#657de6 240deg 300deg,#b66acd 300deg 360deg);border:1px solid rgba(25,32,45,.2);box-shadow:0 1px 3px rgba(0,0,0,.14)}
.k2b-rm-color-wheel:after{content:"";position:absolute;inset:6px;border-radius:50%;background:#fff;box-shadow:0 0 0 1px rgba(25,32,45,.12)}
.k2b-rm-color-caret{flex:none;opacity:.75;transition:transform .15s ease}
#k2b-rm-toolbar [data-k2b-rm-palette][aria-expanded="true"] .k2b-rm-color-caret{transform:rotate(180deg)}
#k2b-rm-toolbar .k2b-rm-exit{background:var(--rm-bg);border-color:var(--rm-border);padding:0 12px}
.k2b-rm-progress{height:4px;background:var(--rm-border);overflow:hidden}
.k2b-rm-progress>span{display:block;height:100%;width:0;background:var(--rm-link);transition:width .12s linear}
.k2b-rm-palette{position:absolute;top:calc(100% + 6px);right:max(18px,calc((100vw - 1130px)/2));width:min(355px,calc(100vw - 24px));padding:15px;border:1px solid var(--rm-border);border-radius:13px;background:var(--rm-panel);box-shadow:0 12px 35px #00000025;color:var(--rm-fg)}
.k2b-rm-palette-heading{font-size:13px;font-weight:700;margin:0 0 9px}
.k2b-rm-swatches{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:6px}
#k2b-rm-toolbar .k2b-rm-swatches button{display:flex;flex-direction:column;gap:6px;min-width:0;height:auto;min-height:70px;padding:7px 2px;font-size:11px;font-weight:600;border:1px solid var(--rm-border);border-radius:9px}
#k2b-rm-toolbar .k2b-rm-swatches button[aria-pressed="true"]{outline:2px solid var(--rm-link);outline-offset:-2px;background:var(--rm-bg)}
.k2b-rm-swatches i{display:block;width:27px;height:27px;border-radius:50%;background:var(--swatch);border:2px solid var(--swatch-ink);flex:none}
@media(max-width:740px){.k2b-rm-toolbar-inner{display:grid;grid-template-columns:1fr;gap:4px;padding:7px 13px 8px}.k2b-rm-overview{justify-content:center}.k2b-rm-controls{justify-content:center}.k2b-rm-overview strong{font-size:13px}.k2b-rm-palette{right:12px}.k2b-rm-color-label{display:none}}
@media(max-width:375px){#k2b-rm-toolbar button{min-width:33px;padding:0 7px}.k2b-rm-overview{gap:6px}.k2b-rm-meta{gap:4px;margin-left:1px}.k2b-rm-position-bottom-right{right:16px;bottom:calc(16px + env(safe-area-inset-bottom))}.k2b-rm-position-bottom-left{left:16px;bottom:calc(16px + env(safe-area-inset-bottom))}}
@media(prefers-reduced-motion:reduce){.k2b-rm-launch{animation:none!important;transition:none!important}.k2b-rm-progress>span,.k2b-rm-color-caret{transition:none!important}}
CSS
    );
    wp_register_script( 'k2b-reading-mode', false, array(), '1.4.0', true );
    wp_enqueue_script( 'k2b-reading-mode' );
    wp_add_inline_script( 'k2b-reading-mode', <<<'JS'
(function () {
    'use strict';

    function initialize() {
        var start = document.querySelector('[data-k2b-rm-start]');
        var end = document.querySelector('[data-k2b-rm-end]');
        var toolbar = document.getElementById('k2b-rm-toolbar');
        if (!start || !end || !toolbar || !start.parentElement || start.parentElement !== end.parentElement) return;

        var content = start.parentElement;
        var title = content.querySelector('.k2b-rm-post-title');
        var smaller = toolbar.querySelector('[data-k2b-rm-smaller]');
        var larger = toolbar.querySelector('[data-k2b-rm-larger]');
        var sizeLabel = toolbar.querySelector('[data-k2b-rm-size]');
        var readingTime = toolbar.querySelector('[data-k2b-rm-time]');
        var percentLabel = toolbar.querySelector('[data-k2b-rm-percent]');
        var progress = toolbar.querySelector('.k2b-rm-progress');
        var progressFill = toolbar.querySelector('[data-k2b-rm-fill]');
        var paletteButton = toolbar.querySelector('[data-k2b-rm-palette]');
        var palette = toolbar.querySelector('#k2b-rm-colors');
        var exitButton = toolbar.querySelector('[data-k2b-rm-exit]');
        var active = false;
        var previousScroll = 0;
        var previousFocus = null;
        var path = [];
        var excluded = [];
        var scheduled = false;
        var totalMinutes = 1;
        var allowedThemes = ['paper', 'sepia', 'sage', 'ocean', 'night'];

        function getPreference(key) {
            try { return localStorage.getItem(key); } catch (err) { return null; }
        }
        function savePreference(key, value) {
            try { localStorage.setItem(key, String(value)); } catch (err) {}
        }
        var configuredSize = parseInt(toolbar.getAttribute('data-default-size'), 10) || 18;
        var canChangeSize = !smaller.hidden;
        var size = canChangeSize ? (parseInt(getPreference('k2b-rm-size'), 10) || configuredSize) : configuredSize;
        size = Math.min(28, Math.max(16, size));
        var configuredTheme = toolbar.getAttribute('data-default-theme') || 'paper';
        if (allowedThemes.indexOf(configuredTheme) < 0) configuredTheme = 'paper';
        var theme = paletteButton.hidden ? configuredTheme : (getPreference('k2b-rm-theme') || configuredTheme);
        if (allowedThemes.indexOf(theme) < 0) theme = configuredTheme;

        function captureWebsiteFonts() {
            // Capture computed website fonts BEFORE changing the page layout.
            var paragraphs = content.querySelector('p:not(.k2b-rm-post-title),li,blockquote');
            var bodyFont = getComputedStyle(paragraphs || content).fontFamily;
            document.body.style.setProperty('--rm-font-body', bodyFont);
            var heading = content.querySelector('h1:not(.k2b-rm-post-title),h2,h3,h4,h5,h6') || document.querySelector('h1,h2,h3');
            var headingFont = heading ? getComputedStyle(heading).fontFamily : bodyFont;
            document.body.style.setProperty('--rm-font-heading', headingFont);
            ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].forEach(function (tag) {
                var sample = content.querySelector(tag + ':not(.k2b-rm-post-title)') || document.querySelector(tag);
                document.body.style.setProperty('--rm-font-' + tag, sample ? getComputedStyle(sample).fontFamily : headingFont);
            });
        }

        function estimateReadingTime() {
            var walker = document.createTreeWalker(content, NodeFilter.SHOW_TEXT);
            var node, words = 0;
            var skip = 'script,style,noscript,svg,button,nav,aside,form,[hidden],.k2b-rm-launch-wrap,.adsbygoogle,[class*="advert"],[id*="advert"],.sharedaddy,.related-posts';
            while ((node = walker.nextNode())) {
                if (!(start.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_FOLLOWING)) continue;
                if (!(end.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_PRECEDING)) continue;
                var parent = node.parentElement;
                if (!parent || parent.closest(skip)) continue;
                var text = node.nodeValue.trim();
                if (text) words += text.split(/\s+/u).length;
            }
            // A transparent estimate using 220 words per minute; minimum 1 minute.
            totalMinutes = Math.max(1, Math.ceil(words / 220));
            readingTime.textContent = totalMinutes + ' min read';
        }

        function applyThemeAndSize() {
            document.body.style.setProperty('--rm-size', size + 'px');
            document.body.setAttribute('data-k2b-rm-theme', theme);
            sizeLabel.textContent = size + 'px';
            smaller.disabled = size <= 16;
            larger.disabled = size >= 28;
            palette.querySelectorAll('[data-k2b-rm-color]').forEach(function (button) {
                button.setAttribute('aria-pressed', String(button.getAttribute('data-k2b-rm-color') === theme));
            });
        }

        function syncToolbarHeight() {
            if (active) document.body.style.setProperty('--rm-top', Math.ceil(toolbar.getBoundingClientRect().height) + 'px');
        }

        function updateProgress() {
            if (!active || scheduled) return;
            scheduled = true;
            requestAnimationFrame(function () {
                scheduled = false;
                if (!active) return;
                // Progress is measured through the visible article, not the whole site.
                var box = content.getBoundingClientRect();
                var top = window.scrollY + box.top;
                var bottom = window.scrollY + box.bottom;
                var finish = Math.max(top, bottom - window.innerHeight);
                var fraction = finish > top ? (window.scrollY - top) / (finish - top) : 1;
                var value = Math.min(100, Math.max(0, Math.round(fraction * 100)));
                progressFill.style.width = value + '%';
                progress.setAttribute('aria-valuenow', String(value));
                percentLabel.textContent = value + '%';
            });
        }

        function closePalette() {
            palette.hidden = true;
            paletteButton.setAttribute('aria-expanded', 'false');
        }
        function setTriggerState(value) {
            document.querySelectorAll('.k2b-rm-launch').forEach(function (button) {
                button.setAttribute('aria-pressed', String(value));
            });
        }
        function openReader(button) {
            if (active) return;
            previousFocus = button;
            previousScroll = window.scrollY;
            captureWebsiteFonts();
            estimateReadingTime();
            var element = content;
            while (element && element !== document.body) {
                element.classList.add('k2b-rm-path');
                path.push(element);
                element = element.parentElement;
            }
            content.classList.add('k2b-rm-content');

            // Only show nodes between the markers; preserve their original DOM.
            var inside = false;
            Array.prototype.forEach.call(content.children, function (child) {
                if (child === start) { inside = true; return; }
                if (child === end) { inside = false; return; }
                if (!inside) {
                    child.classList.add('k2b-rm-excluded');
                    excluded.push(child);
                }
            });
            // Only an H1 inside the actual article should suppress our inserted title.
            if (title) title.hidden = Array.prototype.some.call(content.querySelectorAll('h1:not(.k2b-rm-post-title)'), function (heading) {
                return !!(start.compareDocumentPosition(heading) & Node.DOCUMENT_POSITION_FOLLOWING) &&
                       !!(end.compareDocumentPosition(heading) & Node.DOCUMENT_POSITION_PRECEDING);
            });
            active = true;
            document.documentElement.classList.add('k2b-rm-active');
            document.body.classList.add('k2b-rm-active');
            toolbar.hidden = false;
            applyThemeAndSize();
            syncToolbarHeight();
            setTriggerState(true);
            window.scrollTo(0, 0);
            updateProgress();
            exitButton.focus({ preventScroll: true });
        }
        function closeReader() {
            if (!active) return;
            active = false;
            closePalette();
            toolbar.hidden = true;
            document.documentElement.classList.remove('k2b-rm-active');
            document.body.classList.remove('k2b-rm-active');
            content.classList.remove('k2b-rm-content');
            path.forEach(function (element) { element.classList.remove('k2b-rm-path'); });
            excluded.forEach(function (element) { element.classList.remove('k2b-rm-excluded'); });
            path = [];
            excluded = [];
            if (title) title.hidden = true;
            ['--rm-top', '--rm-size', '--rm-font-body', '--rm-font-heading', '--rm-font-h1', '--rm-font-h2', '--rm-font-h3', '--rm-font-h4', '--rm-font-h5', '--rm-font-h6'].forEach(function (name) {
                document.body.style.removeProperty(name);
            });
            document.body.removeAttribute('data-k2b-rm-theme');
            setTriggerState(false);
            window.scrollTo(0, previousScroll);
            if (previousFocus && previousFocus.isConnected) previousFocus.focus({ preventScroll: true });
        }

        document.addEventListener('click', function (event) {
            var button = event.target.closest('.k2b-rm-launch');
            if (button) { event.preventDefault(); openReader(button); return; }
            if (active && !palette.hidden && !palette.contains(event.target) && !paletteButton.contains(event.target)) closePalette();
        });
        smaller.addEventListener('click', function () {
            size = Math.max(16, size - 2); savePreference('k2b-rm-size', size); applyThemeAndSize(); syncToolbarHeight(); updateProgress();
        });
        larger.addEventListener('click', function () {
            size = Math.min(28, size + 2); savePreference('k2b-rm-size', size); applyThemeAndSize(); syncToolbarHeight(); updateProgress();
        });
        paletteButton.addEventListener('click', function () {
            palette.hidden = !palette.hidden;
            paletteButton.setAttribute('aria-expanded', String(!palette.hidden));
        });
        palette.addEventListener('click', function (event) {
            var button = event.target.closest('[data-k2b-rm-color]');
            if (!button) return;
            var chosen = button.getAttribute('data-k2b-rm-color');
            if (allowedThemes.indexOf(chosen) < 0) return;
            theme = chosen;
            savePreference('k2b-rm-theme', theme);
            applyThemeAndSize();
            closePalette();
            paletteButton.focus({ preventScroll: true });
        });
        exitButton.addEventListener('click', closeReader);
        document.addEventListener('keydown', function (event) {
            if (!active || event.key !== 'Escape') return;
            if (!palette.hidden) { closePalette(); paletteButton.focus({ preventScroll: true }); }
            else closeReader();
        });
        window.addEventListener('scroll', updateProgress, { passive: true });
        window.addEventListener('resize', function () { syncToolbarHeight(); updateProgress(); }, { passive: true });
    }

    if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', initialize);
    else initialize();
}());
JS
    );
} );

If the editor already supplies the opening <?php tag, omit that first line from the pasted code. Configure the snippet to run across the site, since it includes both dashboard settings and frontend functionality, then save and activate it.

Do not paste PHP into a post’s Custom HTML block: it needs to run on the server.

Youtube video

Step 2: Configure Reading Mode

After activation, open Reading Mode from your WordPress dashboard menu.

The settings are organised into three tabs:

Display: Enable Reading Mode, control the floating button, choose whether it appears on posts or pages, and select a corner position.

Reading Mode display settings

Reader tools: Toggle reading time, progress, text size controls, the colour switcher and button animation.

Readers tools settings

Appearance: Choose a default colour theme and a starting text size of 16, 18, 20 or 22px.

Reading Mode Appearance settings

Click Save changes when finished. By default, the floating button is enabled on blog posts and disabled on pages.

Step 3: Place the Button Manually

To add the button within a post or page, insert a Shortcode block containing:

[k2b_reading_mode]

You can disable the floating button and use manual placement instead. Keep the main Enable Reading Mode setting switched on.

When this shortcode is included in the post body, the code suppresses the automatic floating button to avoid duplication.

Step 4: Test the Reading Experience

Open a published article and click the book icon. Check the colour themes, text controls and progress indicator on desktop and mobile.

Click Exit or press Escape to return to the normal layout and your previous scroll position.

If the button is missing, check the visibility settings and clear your website cache. This snippet targets individual posts and pages; custom page-builder layouts may need adjustments.

Note: Reading Mode simplifies the surrounding layout, but advertisements or other elements embedded inside the article may remain visible.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

Hostinger Hosting
Get 20% Discount on Checkout
Hostinger managed Wordpress hosting
Get 20% Discount on Checkout