diff --git a/extensions/amp-story/1.0/amp-story-draggable-drawer-header.css b/extensions/amp-story/1.0/amp-story-draggable-drawer-header.css index c42f114232c1..ba57a15107ab 100644 --- a/extensions/amp-story/1.0/amp-story-draggable-drawer-header.css +++ b/extensions/amp-story/1.0/amp-story-draggable-drawer-header.css @@ -66,6 +66,7 @@ color: #9AA0A6 !important; } -.i-amphtml-story-draggable-drawer-header-bookend { +.i-amphtml-story-draggable-drawer-header-bookend, +.i-amphtml-story-draggable-drawer-header-attachment-remote { display: none !important; } diff --git a/extensions/amp-story/1.0/amp-story-draggable-drawer.css b/extensions/amp-story/1.0/amp-story-draggable-drawer.css index e6c784c656f4..89296e89f822 100644 --- a/extensions/amp-story/1.0/amp-story-draggable-drawer.css +++ b/extensions/amp-story/1.0/amp-story-draggable-drawer.css @@ -24,7 +24,6 @@ overflow: hidden !important; z-index: 4 !important; /** Over amp-story-cta-layer. */ transform: translate3d(0, 100%, 0) !important; - /** If you change the duration of this animation, please reflect if in the JavaScript close_ method too. */ transition: transform 0.25s cubic-bezier(0.4, 0.0, 1, 1) !important; } diff --git a/extensions/amp-story/1.0/amp-story-draggable-drawer.js b/extensions/amp-story/1.0/amp-story-draggable-drawer.js index 1b2d4a5fd5b5..6f91b560a5ac 100644 --- a/extensions/amp-story/1.0/amp-story-draggable-drawer.js +++ b/extensions/amp-story/1.0/amp-story-draggable-drawer.js @@ -85,18 +85,21 @@ export class DraggableDrawer extends AMP.BaseElement { /** @protected {?Element} */ this.contentEl_ = null; + /** @private {number} Max value in pixels that can be dragged when opening the drawer. */ + this.dragCap_ = Infinity; + /** @protected {?Element} */ this.headerEl_ = null; + /** @private {boolean} */ + this.ignoreCurrentSwipeYGesture_ = false; + /** @protected {!DrawerState} */ this.state_ = DrawerState.CLOSED; /** @protected @const {!./amp-story-store-service.AmpStoryStoreService} */ this.storeService_ = getStoreService(this.win); - /** @private {boolean} */ - this.ignoreCurrentSwipeYGesture_ = false; - /** @private {!Object} */ this.touchEventState_ = { startX: 0, @@ -108,6 +111,9 @@ export class DraggableDrawer extends AMP.BaseElement { /** @private {!Array} */ this.touchEventUnlisteners_ = []; + + /** @private {number} Threshold in pixels above which the drawer opens itself. */ + this.openThreshold_ = Infinity; } /** @override */ @@ -379,6 +385,16 @@ export class DraggableDrawer extends AMP.BaseElement { ? this.open() : this.close_(); } + + return; + } + + if ( + this.state_ === DrawerState.DRAGGING_TO_OPEN && + swipingUp && + -deltaY > this.openThreshold_ + ) { + this.open(); return; } @@ -403,6 +419,24 @@ export class DraggableDrawer extends AMP.BaseElement { ); } + /** + * Sets a swipe threshold in pixels above which the drawer opens itself. + * @param {number} openThreshold + * @protected + */ + setOpenThreshold_(openThreshold) { + this.openThreshold_ = openThreshold; + } + + /** + * Sets the max value in pixels that can be dragged when opening the drawer. + * @param {number} dragCap + * @protected + */ + setDragCap_(dragCap) { + this.dragCap_ = dragCap; + } + /** * Drags the drawer on the screen upon user interaction. * @param {number} deltaY @@ -418,7 +452,8 @@ export class DraggableDrawer extends AMP.BaseElement { return; } this.state_ = DrawerState.DRAGGING_TO_OPEN; - translate = `translate3d(0, calc(100% + ${deltaY}px), 0)`; + const drag = Math.max(deltaY, -this.dragCap_); + translate = `translate3d(0, calc(100% + ${drag}px), 0)`; break; case DrawerState.OPEN: case DrawerState.DRAGGING_TO_CLOSE: @@ -482,9 +517,10 @@ export class DraggableDrawer extends AMP.BaseElement { /** * Fully closes the drawer from its current position. + * @param {boolean=} shouldAnimate * @protected */ - closeInternal_() { + closeInternal_(shouldAnimate = true) { if (this.state_ === DrawerState.CLOSED) { return; } @@ -495,13 +531,15 @@ export class DraggableDrawer extends AMP.BaseElement { this.mutateElement(() => { resetStyles(this.element, ['transform', 'transition']); + + if (!shouldAnimate) { + // Resets the 'transition' property, and removes this override in the + // next frame, after the element is positioned. + setImportantStyles(this.element, {transition: 'initial'}); + this.mutateElement(() => resetStyles(this.element, ['transition'])); + } + this.element.classList.remove('i-amphtml-story-draggable-drawer-open'); - // Note: if you change the duration here, you'll also have to change the - // animation duration in the CSS. - setTimeout( - () => toggle(dev().assertElement(this.containerEl_), false), - 250 - ); }).then(() => { const owners = Services.ownersForDoc(this.element); owners.schedulePause(this.element, this.ampComponents_); diff --git a/extensions/amp-story/1.0/amp-story-page-attachment.css b/extensions/amp-story/1.0/amp-story-page-attachment.css new file mode 100644 index 000000000000..18f8ea65a146 --- /dev/null +++ b/extensions/amp-story/1.0/amp-story-page-attachment.css @@ -0,0 +1,224 @@ +/** + * Copyright 2020 The AMP HTML Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS-IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Remote attachment styles. */ + +.i-amphtml-story-page-attachment-remote { + height: 48px !important; + bottom: 0 !important; + top: auto !important; +} + +.i-amphtml-story-page-attachment-remote .i-amphtml-story-draggable-drawer-container { + height: 100% !important; + border-radius: 8px 8px 0 0 !important; + box-shadow: 0 1px 2px 1px rgba(0, 0, 0, 0.12) !important; +} + +.i-amphtml-story-page-attachment-remote-content { + display: flex !important; + padding: 0 24px !important; + align-items: center !important; + color: rgba(0, 0, 0, 0.87) !important; + font-family: 'Roboto', sans-serif !important; + font-size: 15px !important; + justify-content: space-between !important; + line-height: 48px !important; +} + +.i-amphtml-story-page-attachment-remote-domain { + max-width: calc(100% - 30px /* 24px icon + 6px margin */) !important; + overflow: hidden !important; + text-overflow: ellipsis !important; +} + +.i-amphtml-story-page-attachment-remote-icon { + display: block !important; + height: 24px !important; + width: 24px !important; + background-image: url('data:image/svg+xml;charset=utf-8,') !important; +} + +/** amp-story-page open attachment message. */ + +@keyframes open-attachment-fly-in { + 0% { + opacity: 0; + transform: translateY(6px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes open-attachment-icon { + 0% { + transform: translateY(14px); + } + to { + transform: translateY(0); + } +} + +@keyframes open-attachment-icon-explode { + 0% { + transform: scale(0); + } + to { + transform: scale(1); + box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.12); + } +} + +@keyframes open-attachment-icon-color { + 0% { + background: #fff; + } + to { + background: rgba(0, 0, 0, 0.87); + text-shadow: none; + } +} + +@keyframes open-attachment-bar-left { + 0% { + transform: rotate(0deg); + } + to { + transform: rotate(-30deg); + } +} + +@keyframes open-attachment-bar-right { + 0% { + transform: rotate(0deg); + } + to { + transform: rotate(30deg); + } +} + +/** + * Hiding the element and only showing it on the active page so the animation + * triggers every time the page becomes active. + */ +amp-story-page .i-amphtml-story-page-open-attachment { + display: none !important; +} + +amp-story-page[active] .i-amphtml-story-page-open-attachment { + display: flex !important; + align-items: center !important; + justify-content: center !important; + flex-direction: column !important; + position: absolute !important; + bottom: 0 !important; + left: 0 !important; + width: 100% !important; + background: linear-gradient(0, rgba(0, 0, 0, 0.15), transparent) !important; + pointer-events: none !important; + z-index: 3 !important; + animation: open-attachment-fly-in 0.3s cubic-bezier(0.4, 0.0, 0.2, 1) both !important; +} + +amp-story-page .i-amphtml-story-page-open-attachment > * { + cursor: pointer !important; + pointer-events: auto !important; +} + +amp-story-page .i-amphtml-story-page-open-attachment-icon { + display: block !important; + height: 32px !important; + width: 32px !important; + cursor: pointer !important; + animation: open-attachment-icon 0.2s cubic-bezier(0.4, 0.0, 0.2, 1) 2s both !important; +} + +amp-story-page .i-amphtml-story-page-open-attachment-icon::after { + content: "" !important; + position: absolute !important; + top: 0 !important; + left: 0 !important; + height: 100% !important; + width: 100% !important; + background: #FFF !important; + border-radius: 100% !important; + z-index: -1 !important; + animation: open-attachment-icon-explode 0.25s cubic-bezier(0.4, 0.0, 0.2, 1) 2s both !important; +} + +amp-story-page .i-amphtml-story-page-open-attachment-bar-left, +amp-story-page .i-amphtml-story-page-open-attachment-bar-right { + position: absolute !important; + display: block !important; + height: 3px !important; + width: 12px !important; + border-radius: 3px !important; + top: 14px !important; +} + +amp-story-page .i-amphtml-story-page-open-attachment-bar-left { + left: 6px !important; + animation: open-attachment-icon-color 0.25s cubic-bezier(0.4, 0.0, 0.2, 1) 2s both, + open-attachment-bar-left 0.3s cubic-bezier(0.4, 0.0, 0.2, 1) both !important; +} + +amp-story-page .i-amphtml-story-page-open-attachment-bar-right { + right: 6px !important; + animation: open-attachment-icon-color 0.25s cubic-bezier(0.4, 0.0, 0.2, 1) 2s both, + open-attachment-bar-right 0.3s cubic-bezier(0.4, 0.0, 0.2, 1) both !important; +} + +amp-story-page .i-amphtml-story-page-open-attachment-label { + position: relative !important; + padding: 0 32px !important; + margin: 12px 0 20px !important; + height: 16px !important; + max-width: calc(100% - 64px) !important; + color: #FFF !important; + font-family: 'Roboto', sans-serif !important; + font-size: 16px !important; + font-weight: bold !important; + letter-spacing: 0.3px; + line-height: 16px !important; + overflow: hidden !important; + text-overflow: ellipsis !important; + text-shadow: 0px 0px 6px rgba(0, 0, 0, 0.36) !important; + white-space: nowrap !important; +} + +/** Remote attachment opening animation */ + +.i-amphtml-story-page-attachment-expand { + position: relative !important; + width: 100% !important; + height: 100% !important; + background: #FFF !important; + z-index: 100000 !important; /** System layer + 1 */ + animation: i-amphtml-open-3p-attachment 120ms cubic-bezier(0.0, 0.0, 0.2, 1) forwards !important; +} + +@keyframes i-amphtml-open-3p-attachment { + 0% { + transform: scaleX(0); + opacity: 0.3; + } + 100% { + transform: scaleX(1); + opacity: 1; + } +} diff --git a/extensions/amp-story/1.0/amp-story-page-attachment.js b/extensions/amp-story/1.0/amp-story-page-attachment.js index d480625b7462..9610d0743080 100644 --- a/extensions/amp-story/1.0/amp-story-page-attachment.js +++ b/extensions/amp-story/1.0/amp-story-page-attachment.js @@ -19,6 +19,7 @@ import {DraggableDrawer, DrawerState} from './amp-story-draggable-drawer'; import {HistoryState, setHistoryState} from './utils'; import {Services} from '../../../src/services'; import {StoryAnalyticsEvent, getAnalyticsService} from './story-analytics'; +import {closest, removeElement} from '../../../src/dom'; import {dev} from '../../../src/log'; import {getState} from '../../../src/history'; import {htmlFor} from '../../../src/static-template'; @@ -35,6 +36,14 @@ const AttachmentTheme = { DARK: 'dark', }; +/** + * @enum + */ +const AttachmentType = { + INLINE: 0, + REMOTE: 1, +}; + /** * AMP Story page attachment. */ @@ -43,11 +52,14 @@ export class AmpStoryPageAttachment extends DraggableDrawer { constructor(element) { super(element); - /** @private {!./story-analytics.StoryAnalyticsService} */ + /** @private @const {!./story-analytics.StoryAnalyticsService} */ this.analyticsService_ = getAnalyticsService(this.win, this.element); - /** @type {!../../../src/service/history-impl.History} */ + /** @private @const {!../../../src/service/history-impl.History} */ this.historyService_ = Services.historyForDoc(this.element); + + /** @private {?AttachmentType} */ + this.type_ = null; } /** @@ -56,15 +68,51 @@ export class AmpStoryPageAttachment extends DraggableDrawer { buildCallback() { super.buildCallback(); + const theme = this.element.getAttribute('theme'); + if (theme && AttachmentTheme.DARK === theme.toLowerCase()) { + this.headerEl_.classList.add(DARK_THEME_CLASS); + this.element.classList.add(DARK_THEME_CLASS); + } + + // URL will be validated and resolved based on the canonical URL if relative + // when navigating. + const href = this.element.getAttribute('href'); + this.type_ = href ? AttachmentType.REMOTE : AttachmentType.INLINE; + + if (this.type_ === AttachmentType.INLINE) { + this.buildInline_(); + } + + if (this.type_ === AttachmentType.REMOTE) { + this.buildRemote_(); + } + + this.win.addEventListener('pageshow', event => { + // On browser back, Safari does not reload the page but resumes its cached + // version. This event's parameter lets us know when this happens so we + // can cleanup the remote opening animation. + if (event.persisted) { + this.closeInternal_(false /** shouldAnimate */); + } + }); + + toggle(this.element, true); + } + + /** + * Builds inline page attachment's UI. + * @private + */ + buildInline_() { this.headerEl_.appendChild( htmlFor(this.element)` - - ` + + ` ); this.headerEl_.appendChild( htmlFor(this.element)` - ` + ` ); if (this.element.hasAttribute('data-title')) { @@ -73,12 +121,6 @@ export class AmpStoryPageAttachment extends DraggableDrawer { ).textContent = this.element.getAttribute('data-title'); } - const theme = this.element.getAttribute('theme'); - if (theme && AttachmentTheme.DARK === theme.toLowerCase()) { - this.headerEl_.classList.add(DARK_THEME_CLASS); - this.element.classList.add(DARK_THEME_CLASS); - } - const templateEl = this.element.querySelector( '.i-amphtml-story-draggable-drawer' ); @@ -89,8 +131,36 @@ export class AmpStoryPageAttachment extends DraggableDrawer { // Ensures the content of the attachment won't be rendered/loaded until we // actually need it. - toggle(dev().assertElement(this.containerEl_), false); - toggle(this.element, true); + toggle(dev().assertElement(this.containerEl_), true); + } + + /** + * Builds remote page attachment's UI. + * @private + */ + buildRemote_() { + this.setDragCap_(48 /* pixels */); + this.setOpenThreshold_(150 /* pixels */); + + this.headerEl_.classList.add( + 'i-amphtml-story-draggable-drawer-header-attachment-remote' + ); + this.element.classList.add('i-amphtml-story-page-attachment-remote'); + this.contentEl_.appendChild( + htmlFor(this.element)` +
+ + +
` + ); + + const urlService = Services.urlForDoc(this.element); + const domain = urlService.getSourceOrigin( + this.element.getAttribute('href') + ); + this.contentEl_.querySelector( + '.i-amphtml-story-page-attachment-remote-domain' + ).textContent = domain; } /** @@ -99,9 +169,16 @@ export class AmpStoryPageAttachment extends DraggableDrawer { initializeListeners_() { super.initializeListeners_(); - this.headerEl_ - .querySelector('.i-amphtml-story-page-attachment-close-button') - .addEventListener('click', () => this.close_(), true /** useCapture */); + const closeButtonEl = this.headerEl_.querySelector( + '.i-amphtml-story-page-attachment-close-button' + ); + if (closeButtonEl) { + closeButtonEl.addEventListener( + 'click', + () => this.close_(), + true /** useCapture */ + ); + } // Always open links in a new tab. this.contentEl_.addEventListener( @@ -133,25 +210,64 @@ export class AmpStoryPageAttachment extends DraggableDrawer { * @override */ open(shouldAnimate = true) { + if (this.state_ === DrawerState.OPEN) { + return; + } + super.open(shouldAnimate); this.storeService_.dispatch(Action.TOGGLE_SYSTEM_UI_IS_VISIBLE, false); - const currentHistoryState = /** @type {!Object} */ (getState( - this.win.history - )); - const historyState = { - ...currentHistoryState, - [HistoryState.ATTACHMENT_PAGE_ID]: this.storeService_.get( - StateProperty.CURRENT_PAGE_ID - ), - }; - - this.historyService_.push(() => this.closeInternal_(), historyState); + // Don't create a new history entry for remote attachment as user is + // navigating away. + if (this.type_ !== AttachmentType.REMOTE) { + const currentHistoryState = /** @type {!Object} */ (getState( + this.win.history + )); + const historyState = { + ...currentHistoryState, + [HistoryState.ATTACHMENT_PAGE_ID]: this.storeService_.get( + StateProperty.CURRENT_PAGE_ID + ), + }; + this.historyService_.push(() => this.closeInternal_(), historyState); + } + this.analyticsService_.triggerEvent(StoryAnalyticsEvent.OPEN, this.element); this.analyticsService_.triggerEvent( StoryAnalyticsEvent.PAGE_ATTACHMENT_ENTER ); + + if (this.type_ === AttachmentType.REMOTE) { + this.openRemote_(); + } + } + + /** + * Triggers a remote attachment opening animation, and redirects to the + * specified URL. + * @private + */ + openRemote_() { + const animationEl = this.win.document.createElement('div'); + animationEl.classList.add('i-amphtml-story-page-attachment-expand'); + const storyEl = closest(this.element, el => el.tagName === 'AMP-STORY'); + this.storeService_.dispatch(Action.TOGGLE_SYSTEM_UI_IS_VISIBLE, false); + + this.mutateElement(() => { + storyEl.appendChild(animationEl); + }).then(() => { + // Give some time for the 120ms CSS animation to run (cf + // amp-story-page-attachment.css). The navigation itself will take some + // time, depending on the target and network conditions. + this.win.setTimeout(() => { + const navigationService = Services.navigationForDoc(this.getAmpDoc()); + navigationService.navigateTo( + this.win, + this.element.getAttribute('href') + ); + }, 50); + }); } /** @@ -178,11 +294,25 @@ export class AmpStoryPageAttachment extends DraggableDrawer { /** * @override */ - closeInternal_() { - super.closeInternal_(); + closeInternal_(shouldAnimate = true) { + if (this.state_ === DrawerState.CLOSED) { + return; + } + + super.closeInternal_(shouldAnimate); this.storeService_.dispatch(Action.TOGGLE_SYSTEM_UI_IS_VISIBLE, true); + const storyEl = closest(this.element, el => el.tagName === 'AMP-STORY'); + const animationEl = storyEl.querySelector( + '.i-amphtml-story-page-attachment-expand' + ); + if (animationEl) { + this.mutateElement(() => { + removeElement(dev().assertElement(animationEl)); + }); + } + setHistoryState(this.win, HistoryState.ATTACHMENT_PAGE_ID, null); this.analyticsService_.triggerEvent( diff --git a/extensions/amp-story/1.0/amp-story.css b/extensions/amp-story/1.0/amp-story.css index 1dc1979133e9..c18a0a3f0a1e 100644 --- a/extensions/amp-story/1.0/amp-story.css +++ b/extensions/amp-story/1.0/amp-story.css @@ -18,6 +18,7 @@ @import './amp-story-affiliate-link.css'; @import './amp-story-desktop-panels.css'; @import './amp-story-draggable-drawer.css'; +@import './amp-story-page-attachment.css'; @import './amp-story-templates.css'; @import './amp-story-user-overridable.css'; @import './amp-story-vertical.css'; @@ -201,6 +202,8 @@ amp-story-page { right: 0 !important; top: 0 !important; opacity: 1 !important; + /** Required by Chrome to consider touch events on story-pages as user gestures. */ + touch-action: none !important; transition: none !important; z-index: 0 !important; } @@ -856,155 +859,6 @@ amp-story .amp-video-eq, background-image: url('data:image/svg+xml;charset=utf-8,') !important; } -/** amp-story-page open attachment message. */ - -@keyframes open-attachment-fly-in { - 0% { - opacity: 0; - transform: translateY(6px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -@keyframes open-attachment-icon { - 0% { - transform: translateY(14px); - } - to { - transform: translateY(0); - } -} - -@keyframes open-attachment-icon-explode { - 0% { - transform: scale(0); - } - to { - transform: scale(1); - box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.12); - } -} - -@keyframes open-attachment-icon-color { - 0% { - background: #fff; - } - to { - background: rgba(0, 0, 0, 0.87); - text-shadow: none; - } -} - -@keyframes open-attachment-bar-left { - 0% { - transform: rotate(0deg); - } - to { - transform: rotate(-30deg); - } -} - -@keyframes open-attachment-bar-right { - 0% { - transform: rotate(0deg); - } - to { - transform: rotate(30deg); - } -} - -/** - * Hiding the element and only showing it on the active page so the animation - * triggers every time the page becomes active. - */ -amp-story-page .i-amphtml-story-page-open-attachment { - display: none !important; -} - -amp-story-page[active] .i-amphtml-story-page-open-attachment { - display: flex !important; - align-items: center !important; - justify-content: center !important; - flex-direction: column !important; - position: absolute !important; - bottom: 0 !important; - left: 0 !important; - width: 100% !important; - background: linear-gradient(0, rgba(0, 0, 0, 0.15), transparent) !important; - pointer-events: none !important; - z-index: 3 !important; - animation: open-attachment-fly-in 0.3s cubic-bezier(0.4, 0.0, 0.2, 1) both !important; -} - -amp-story-page .i-amphtml-story-page-open-attachment > * { - cursor: pointer !important; - pointer-events: auto !important; -} - -amp-story-page .i-amphtml-story-page-open-attachment-icon { - display: block !important; - height: 32px !important; - width: 32px !important; - cursor: pointer !important; - animation: open-attachment-icon 0.2s cubic-bezier(0.4, 0.0, 0.2, 1) 2s both !important; -} - -amp-story-page .i-amphtml-story-page-open-attachment-icon::after { - content: "" !important; - position: absolute !important; - top: 0 !important; - left: 0 !important; - height: 100% !important; - width: 100% !important; - background: #FFF !important; - border-radius: 100% !important; - z-index: -1 !important; - animation: open-attachment-icon-explode 0.25s cubic-bezier(0.4, 0.0, 0.2, 1) 2s both !important; -} - -.i-amphtml-story-page-open-attachment-bar-left, -.i-amphtml-story-page-open-attachment-bar-right { - position: absolute !important; - display: block !important; - height: 3px !important; - width: 12px !important; - border-radius: 3px !important; - top: 14px !important; -} - -.i-amphtml-story-page-open-attachment-bar-left { - left: 6px !important; - animation: open-attachment-icon-color 0.25s cubic-bezier(0.4, 0.0, 0.2, 1) 2s both, - open-attachment-bar-left 0.3s cubic-bezier(0.4, 0.0, 0.2, 1) both !important; -} - -.i-amphtml-story-page-open-attachment-bar-right { - right: 6px !important; - animation: open-attachment-icon-color 0.25s cubic-bezier(0.4, 0.0, 0.2, 1) 2s both, - open-attachment-bar-right 0.3s cubic-bezier(0.4, 0.0, 0.2, 1) both !important; -} - -amp-story-page .i-amphtml-story-page-open-attachment-label { - position: relative !important; - padding: 0 32px !important; - margin: 12px 0 20px !important; - height: 16px !important; - max-width: calc(100% - 64px) !important; - color: #FFF !important; - font-family: 'Roboto', sans-serif !important; - font-size: 16px !important; - font-weight: bold !important; - letter-spacing: 0.3px; - line-height: 16px !important; - overflow: hidden !important; - text-overflow: ellipsis !important; - text-shadow: 0px 0px 6px rgba(0, 0, 0, 0.36) !important; - white-space: nowrap !important; -} - amp-story-quiz { align-self: center; width: auto !important;